[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/simplepie/simplepie/library/SimplePie/Cache/ -> MySQL.php (source)

   1  <?php
   2  /**
   3   * SimplePie
   4   *
   5   * A PHP-Based RSS and Atom Feed Framework.
   6   * Takes the hard work out of managing a complete RSS/Atom solution.
   7   *
   8   * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
   9   * All rights reserved.
  10   *
  11   * Redistribution and use in source and binary forms, with or without modification, are
  12   * permitted provided that the following conditions are met:
  13   *
  14   *     * Redistributions of source code must retain the above copyright notice, this list of
  15   *       conditions and the following disclaimer.
  16   *
  17   *     * Redistributions in binary form must reproduce the above copyright notice, this list
  18   *       of conditions and the following disclaimer in the documentation and/or other materials
  19   *       provided with the distribution.
  20   *
  21   *     * Neither the name of the SimplePie Team nor the names of its contributors may be used
  22   *       to endorse or promote products derived from this software without specific prior
  23   *       written permission.
  24   *
  25   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  26   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  27   * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  28   * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  30   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  32   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33   * POSSIBILITY OF SUCH DAMAGE.
  34   *
  35   * @package SimplePie
  36   * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  37   * @author Ryan Parman
  38   * @author Geoffrey Sneddon
  39   * @author Ryan McCue
  40   * @link http://simplepie.org/ SimplePie
  41   * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  42   */
  43  
  44  /**
  45   * Caches data to a MySQL database
  46   *
  47   * Registered for URLs with the "mysql" protocol
  48   *
  49   * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
  50   * connect to the `mydb` database on `localhost` on port 3306, with the user
  51   * `root` and the password `password`. All tables will be prefixed with `sp_`
  52   *
  53   * @package SimplePie
  54   * @subpackage Caching
  55   */
  56  class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
  57  {
  58      /**
  59       * PDO instance
  60       *
  61       * @var PDO
  62       */
  63      protected $mysql;
  64  
  65      /**
  66       * Options
  67       *
  68       * @var array
  69       */
  70      protected $options;
  71  
  72      /**
  73       * Cache ID
  74       *
  75       * @var string
  76       */
  77      protected $id;
  78  
  79      /**
  80       * Create a new cache object
  81       *
  82       * @param string $location Location string (from SimplePie::$cache_location)
  83       * @param string $name Unique ID for the cache
  84       * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  85       */
  86  	public function __construct($location, $name, $type)
  87      {
  88          $this->options = array(
  89              'user' => null,
  90              'pass' => null,
  91              'host' => '127.0.0.1',
  92              'port' => '3306',
  93              'path' => '',
  94              'extras' => array(
  95                  'prefix' => '',
  96                  'cache_purge_time' => 2592000
  97              ),
  98          );
  99  
 100          $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
 101  
 102          // Path is prefixed with a "/"
 103          $this->options['dbname'] = substr($this->options['path'], 1);
 104  
 105          try
 106          {
 107              $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
 108          }
 109          catch (PDOException $e)
 110          {
 111              $this->mysql = null;
 112              return;
 113          }
 114  
 115          $this->id = $name . $type;
 116  
 117          if (!$query = $this->mysql->query('SHOW TABLES'))
 118          {
 119              $this->mysql = null;
 120              return;
 121          }
 122  
 123          $db = array();
 124          while ($row = $query->fetchColumn())
 125          {
 126              $db[] = $row;
 127          }
 128  
 129          if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
 130          {
 131              $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
 132              if ($query === false)
 133              {
 134                  trigger_error("Can't create " . $this->options['extras']['prefix'] . "cache_data table, check permissions", E_USER_WARNING);
 135                  $this->mysql = null;
 136                  return;
 137              }
 138          }
 139  
 140          if (!in_array($this->options['extras']['prefix'] . 'items', $db))
 141          {
 142              $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` MEDIUMBLOB NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
 143              if ($query === false)
 144              {
 145                  trigger_error("Can't create " . $this->options['extras']['prefix'] . "items table, check permissions", E_USER_WARNING);
 146                  $this->mysql = null;
 147                  return;
 148              }
 149          }
 150      }
 151  
 152      /**
 153       * Save data to the cache
 154       *
 155       * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
 156       * @return bool Successfulness
 157       */
 158  	public function save($data)
 159      {
 160          if ($this->mysql === null)
 161          {
 162              return false;
 163          }
 164  
 165          $query = $this->mysql->prepare('DELETE i, cd FROM `' . $this->options['extras']['prefix'] . 'cache_data` cd, ' .
 166              '`' . $this->options['extras']['prefix'] . 'items` i ' .
 167              'WHERE cd.id = i.feed_id ' .
 168              'AND cd.mtime < (unix_timestamp() - :purge_time)');
 169          $query->bindValue(':purge_time', $this->options['extras']['cache_purge_time']);
 170  
 171          if (!$query->execute())
 172          {
 173              return false;
 174          }
 175  
 176          if ($data instanceof SimplePie)
 177          {
 178              $data = clone $data;
 179  
 180              $prepared = self::prepare_simplepie_object_for_cache($data);
 181  
 182              $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
 183              $query->bindValue(':feed', $this->id);
 184              if ($query->execute())
 185              {
 186                  if ($query->fetchColumn() > 0)
 187                  {
 188                      $items = count($prepared[1]);
 189                      if ($items)
 190                      {
 191                          $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
 192                          $query = $this->mysql->prepare($sql);
 193                          $query->bindValue(':items', $items);
 194                      }
 195                      else
 196                      {
 197                          $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
 198                          $query = $this->mysql->prepare($sql);
 199                      }
 200  
 201                      $query->bindValue(':data', $prepared[0]);
 202                      $query->bindValue(':time', time());
 203                      $query->bindValue(':feed', $this->id);
 204                      if (!$query->execute())
 205                      {
 206                          return false;
 207                      }
 208                  }
 209                  else
 210                  {
 211                      $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
 212                      $query->bindValue(':feed', $this->id);
 213                      $query->bindValue(':count', count($prepared[1]));
 214                      $query->bindValue(':data', $prepared[0]);
 215                      $query->bindValue(':time', time());
 216                      if (!$query->execute())
 217                      {
 218                          return false;
 219                      }
 220                  }
 221  
 222                  $ids = array_keys($prepared[1]);
 223                  if (!empty($ids))
 224                  {
 225                      foreach ($ids as $id)
 226                      {
 227                          $database_ids[] = $this->mysql->quote($id);
 228                      }
 229  
 230                      $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
 231                      $query->bindValue(':feed', $this->id);
 232  
 233                      if ($query->execute())
 234                      {
 235                          $existing_ids = array();
 236                          while ($row = $query->fetchColumn())
 237                          {
 238                              $existing_ids[] = $row;
 239                          }
 240  
 241                          $new_ids = array_diff($ids, $existing_ids);
 242  
 243                          foreach ($new_ids as $new_id)
 244                          {
 245                              if (!($date = $prepared[1][$new_id]->get_date('U')))
 246                              {
 247                                  $date = time();
 248                              }
 249  
 250                              $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
 251                              $query->bindValue(':feed', $this->id);
 252                              $query->bindValue(':id', $new_id);
 253                              $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
 254                              $query->bindValue(':date', $date);
 255                              if (!$query->execute())
 256                              {
 257                                  return false;
 258                              }
 259                          }
 260                          return true;
 261                      }
 262                  }
 263                  else
 264                  {
 265                      return true;
 266                  }
 267              }
 268          }
 269          else
 270          {
 271              $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
 272              $query->bindValue(':feed', $this->id);
 273              if ($query->execute())
 274              {
 275                  if ($query->rowCount() > 0)
 276                  {
 277                      $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
 278                      $query->bindValue(':data', serialize($data));
 279                      $query->bindValue(':time', time());
 280                      $query->bindValue(':feed', $this->id);
 281                      if ($this->execute())
 282                      {
 283                          return true;
 284                      }
 285                  }
 286                  else
 287                  {
 288                      $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
 289                      $query->bindValue(':id', $this->id);
 290                      $query->bindValue(':data', serialize($data));
 291                      $query->bindValue(':time', time());
 292                      if ($query->execute())
 293                      {
 294                          return true;
 295                      }
 296                  }
 297              }
 298          }
 299          return false;
 300      }
 301  
 302      /**
 303       * Retrieve the data saved to the cache
 304       *
 305       * @return array Data for SimplePie::$data
 306       */
 307  	public function load()
 308      {
 309          if ($this->mysql === null)
 310          {
 311              return false;
 312          }
 313  
 314          $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
 315          $query->bindValue(':id', $this->id);
 316          if ($query->execute() && ($row = $query->fetch()))
 317          {
 318              $data = unserialize($row[1]);
 319  
 320              if (isset($this->options['items'][0]))
 321              {
 322                  $items = (int) $this->options['items'][0];
 323              }
 324              else
 325              {
 326                  $items = (int) $row[0];
 327              }
 328  
 329              if ($items !== 0)
 330              {
 331                  if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
 332                  {
 333                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
 334                  }
 335                  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
 336                  {
 337                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
 338                  }
 339                  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
 340                  {
 341                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
 342                  }
 343                  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
 344                  {
 345                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
 346                  }
 347                  else
 348                  {
 349                      $feed = null;
 350                  }
 351  
 352                  if ($feed !== null)
 353                  {
 354                      $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
 355                      if ($items > 0)
 356                      {
 357                          $sql .= ' LIMIT ' . $items;
 358                      }
 359  
 360                      $query = $this->mysql->prepare($sql);
 361                      $query->bindValue(':feed', $this->id);
 362                      if ($query->execute())
 363                      {
 364                          while ($row = $query->fetchColumn())
 365                          {
 366                              $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
 367                          }
 368                      }
 369                      else
 370                      {
 371                          return false;
 372                      }
 373                  }
 374              }
 375              return $data;
 376          }
 377          return false;
 378      }
 379  
 380      /**
 381       * Retrieve the last modified time for the cache
 382       *
 383       * @return int Timestamp
 384       */
 385  	public function mtime()
 386      {
 387          if ($this->mysql === null)
 388          {
 389              return false;
 390          }
 391  
 392          $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
 393          $query->bindValue(':id', $this->id);
 394          if ($query->execute() && ($time = $query->fetchColumn()))
 395          {
 396              return $time;
 397          }
 398  
 399          return false;
 400      }
 401  
 402      /**
 403       * Set the last modified time to the current time
 404       *
 405       * @return bool Success status
 406       */
 407  	public function touch()
 408      {
 409          if ($this->mysql === null)
 410          {
 411              return false;
 412          }
 413  
 414          $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
 415          $query->bindValue(':time', time());
 416          $query->bindValue(':id', $this->id);
 417  
 418          return $query->execute() && $query->rowCount() > 0;
 419      }
 420  
 421      /**
 422       * Remove the cache
 423       *
 424       * @return bool Success status
 425       */
 426  	public function unlink()
 427      {
 428          if ($this->mysql === null)
 429          {
 430              return false;
 431          }
 432  
 433          $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
 434          $query->bindValue(':id', $this->id);
 435          $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
 436          $query2->bindValue(':id', $this->id);
 437  
 438          return $query->execute() && $query2->execute();
 439      }
 440  }