[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 // SPDX-FileCopyrightText: 2004-2023 Ryan Parman, Sam Sneddon, Ryan McCue 4 // SPDX-License-Identifier: BSD-3-Clause 5 6 declare(strict_types=1); 7 8 namespace SimplePie\Cache; 9 10 /** 11 * Caches data to a MySQL database 12 * 13 * Registered for URLs with the "mysql" protocol 14 * 15 * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will 16 * connect to the `mydb` database on `localhost` on port 3306, with the user 17 * `root` and the password `password`. All tables will be prefixed with `sp_` 18 * 19 * @deprecated since SimplePie 1.8.0, use implementation of "Psr\SimpleCache\CacheInterface" instead 20 */ 21 class MySQL extends DB 22 { 23 /** 24 * PDO instance 25 * 26 * @var \PDO|null 27 */ 28 protected $mysql; 29 30 /** 31 * Options 32 * 33 * @var array<string, mixed> 34 */ 35 protected $options; 36 37 /** 38 * Cache ID 39 * 40 * @var string 41 */ 42 protected $id; 43 44 /** 45 * Create a new cache object 46 * 47 * @param string $location Location string (from SimplePie::$cache_location) 48 * @param string $name Unique ID for the cache 49 * @param Base::TYPE_FEED|Base::TYPE_IMAGE $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data 50 */ 51 public function __construct(string $location, string $name, $type) 52 { 53 $this->options = [ 54 'user' => null, 55 'pass' => null, 56 'host' => '127.0.0.1', 57 'port' => '3306', 58 'path' => '', 59 'extras' => [ 60 'prefix' => '', 61 'cache_purge_time' => 2592000 62 ], 63 ]; 64 65 $this->options = array_replace_recursive($this->options, \SimplePie\Cache::parse_URL($location)); 66 67 // Path is prefixed with a "/" 68 $this->options['dbname'] = substr($this->options['path'], 1); 69 70 try { 71 $this->mysql = new \PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8']); 72 } catch (\PDOException $e) { 73 $this->mysql = null; 74 return; 75 } 76 77 $this->id = $name . $type; 78 79 if (!$query = $this->mysql->query('SHOW TABLES')) { 80 $this->mysql = null; 81 return; 82 } 83 84 $db = []; 85 while ($row = $query->fetchColumn()) { 86 $db[] = $row; 87 } 88 89 if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db)) { 90 $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)))'); 91 if ($query === false) { 92 trigger_error("Can't create " . $this->options['extras']['prefix'] . "cache_data table, check permissions", \E_USER_WARNING); 93 $this->mysql = null; 94 return; 95 } 96 } 97 98 if (!in_array($this->options['extras']['prefix'] . 'items', $db)) { 99 $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)))'); 100 if ($query === false) { 101 trigger_error("Can't create " . $this->options['extras']['prefix'] . "items table, check permissions", \E_USER_WARNING); 102 $this->mysql = null; 103 return; 104 } 105 } 106 } 107 108 /** 109 * Save data to the cache 110 * 111 * @param array<string>|\SimplePie\SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property 112 * @return bool Successfulness 113 */ 114 public function save($data) 115 { 116 if ($this->mysql === null) { 117 return false; 118 } 119 120 $query = $this->mysql->prepare('DELETE i, cd FROM `' . $this->options['extras']['prefix'] . 'cache_data` cd, ' . 121 '`' . $this->options['extras']['prefix'] . 'items` i ' . 122 'WHERE cd.id = i.feed_id ' . 123 'AND cd.mtime < (unix_timestamp() - :purge_time)'); 124 $query->bindValue(':purge_time', $this->options['extras']['cache_purge_time']); 125 126 if (!$query->execute()) { 127 return false; 128 } 129 130 if ($data instanceof \SimplePie\SimplePie) { 131 $data = clone $data; 132 133 $prepared = self::prepare_simplepie_object_for_cache($data); 134 135 $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed'); 136 $query->bindValue(':feed', $this->id); 137 if ($query->execute()) { 138 if ($query->fetchColumn() > 0) { 139 $items = count($prepared[1]); 140 if ($items) { 141 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed'; 142 $query = $this->mysql->prepare($sql); 143 $query->bindValue(':items', $items); 144 } else { 145 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed'; 146 $query = $this->mysql->prepare($sql); 147 } 148 149 $query->bindValue(':data', $prepared[0]); 150 $query->bindValue(':time', time()); 151 $query->bindValue(':feed', $this->id); 152 if (!$query->execute()) { 153 return false; 154 } 155 } else { 156 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)'); 157 $query->bindValue(':feed', $this->id); 158 $query->bindValue(':count', count($prepared[1])); 159 $query->bindValue(':data', $prepared[0]); 160 $query->bindValue(':time', time()); 161 if (!$query->execute()) { 162 return false; 163 } 164 } 165 166 $ids = array_keys($prepared[1]); 167 if (!empty($ids)) { 168 foreach ($ids as $id) { 169 $database_ids[] = $this->mysql->quote($id); 170 } 171 172 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed'); 173 $query->bindValue(':feed', $this->id); 174 175 if ($query->execute()) { 176 $existing_ids = []; 177 while ($row = $query->fetchColumn()) { 178 $existing_ids[] = $row; 179 } 180 181 $new_ids = array_diff($ids, $existing_ids); 182 183 foreach ($new_ids as $new_id) { 184 if (!($date = $prepared[1][$new_id]->get_date('U'))) { 185 $date = time(); 186 } 187 188 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)'); 189 $query->bindValue(':feed', $this->id); 190 $query->bindValue(':id', $new_id); 191 $query->bindValue(':data', serialize($prepared[1][$new_id]->data)); 192 $query->bindValue(':date', $date); 193 if (!$query->execute()) { 194 return false; 195 } 196 } 197 return true; 198 } 199 } else { 200 return true; 201 } 202 } 203 } else { 204 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed'); 205 $query->bindValue(':feed', $this->id); 206 if ($query->execute()) { 207 if ($query->rowCount() > 0) { 208 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed'); 209 $query->bindValue(':data', serialize($data)); 210 $query->bindValue(':time', time()); 211 $query->bindValue(':feed', $this->id); 212 if ($query->execute()) { 213 return true; 214 } 215 } else { 216 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)'); 217 $query->bindValue(':id', $this->id); 218 $query->bindValue(':data', serialize($data)); 219 $query->bindValue(':time', time()); 220 if ($query->execute()) { 221 return true; 222 } 223 } 224 } 225 } 226 return false; 227 } 228 229 /** 230 * Retrieve the data saved to the cache 231 * 232 * @return array<string>|false Data for SimplePie::$data 233 */ 234 public function load() 235 { 236 if ($this->mysql === null) { 237 return false; 238 } 239 240 $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); 241 $query->bindValue(':id', $this->id); 242 if ($query->execute() && ($row = $query->fetch())) { 243 $data = unserialize($row[1]); 244 245 if (isset($this->options['items'][0])) { 246 $items = (int) $this->options['items'][0]; 247 } else { 248 $items = (int) $row[0]; 249 } 250 251 if ($items !== 0) { 252 if (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['feed'][0])) { 253 $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['feed'][0]; 254 } elseif (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['feed'][0])) { 255 $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['feed'][0]; 256 } elseif (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_RDF]['RDF'][0])) { 257 $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_RDF]['RDF'][0]; 258 } elseif (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['rss'][0])) { 259 $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['rss'][0]; 260 } else { 261 $feed = null; 262 } 263 264 if ($feed !== null) { 265 $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC'; 266 if ($items > 0) { 267 $sql .= ' LIMIT ' . $items; 268 } 269 270 $query = $this->mysql->prepare($sql); 271 $query->bindValue(':feed', $this->id); 272 if ($query->execute()) { 273 while ($row = $query->fetchColumn()) { 274 $feed['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['entry'][] = unserialize((string) $row); 275 } 276 } else { 277 return false; 278 } 279 } 280 } 281 return $data; 282 } 283 return false; 284 } 285 286 /** 287 * Retrieve the last modified time for the cache 288 * 289 * @return int|false Timestamp 290 */ 291 public function mtime() 292 { 293 if ($this->mysql === null) { 294 return false; 295 } 296 297 $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); 298 $query->bindValue(':id', $this->id); 299 if ($query->execute() && ($time = $query->fetchColumn())) { 300 return (int) $time; 301 } 302 303 return false; 304 } 305 306 /** 307 * Set the last modified time to the current time 308 * 309 * @return bool Success status 310 */ 311 public function touch() 312 { 313 if ($this->mysql === null) { 314 return false; 315 } 316 317 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id'); 318 $query->bindValue(':time', time()); 319 $query->bindValue(':id', $this->id); 320 321 return $query->execute() && $query->rowCount() > 0; 322 } 323 324 /** 325 * Remove the cache 326 * 327 * @return bool Success status 328 */ 329 public function unlink() 330 { 331 if ($this->mysql === null) { 332 return false; 333 } 334 335 $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); 336 $query->bindValue(':id', $this->id); 337 $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id'); 338 $query2->bindValue(':id', $this->id); 339 340 return $query->execute() && $query2->execute(); 341 } 342 } 343 344 class_alias('SimplePie\Cache\MySQL', 'SimplePie_Cache_MySQL');
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Fri Oct 10 08:20:03 2025 | Cross-referenced by PHPXref |