~canonical-sysadmins/wordpress/4.7.4

« back to all changes in this revision

Viewing changes to wp-includes/SimplePie/Cache/MySQL.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2012, 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
 * @version 1.3.1
 
37
 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
 
38
 * @author Ryan Parman
 
39
 * @author Geoffrey Sneddon
 
40
 * @author Ryan McCue
 
41
 * @link http://simplepie.org/ SimplePie
 
42
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 
43
 */
 
44
 
 
45
/**
 
46
 * Caches data to a MySQL database
 
47
 *
 
48
 * Registered for URLs with the "mysql" protocol
 
49
 *
 
50
 * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
 
51
 * connect to the `mydb` database on `localhost` on port 3306, with the user
 
52
 * `root` and the password `password`. All tables will be prefixed with `sp_`
 
53
 *
 
54
 * @package SimplePie
 
55
 * @subpackage Caching
 
56
 */
 
57
class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
 
58
{
 
59
        /**
 
60
         * PDO instance
 
61
         *
 
62
         * @var PDO
 
63
         */
 
64
        protected $mysql;
 
65
 
 
66
        /**
 
67
         * Options
 
68
         *
 
69
         * @var array
 
70
         */
 
71
        protected $options;
 
72
 
 
73
        /**
 
74
         * Cache ID
 
75
         *
 
76
         * @var string
 
77
         */
 
78
        protected $id;
 
79
 
 
80
        /**
 
81
         * Create a new cache object
 
82
         *
 
83
         * @param string $location Location string (from SimplePie::$cache_location)
 
84
         * @param string $name Unique ID for the cache
 
85
         * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
 
86
         */
 
87
        public function __construct($location, $name, $type)
 
88
        {
 
89
                $this->options = array(
 
90
                        'user' => null,
 
91
                        'pass' => null,
 
92
                        'host' => '127.0.0.1',
 
93
                        'port' => '3306',
 
94
                        'path' => '',
 
95
                        'extras' => array(
 
96
                                'prefix' => '',
 
97
                        ),
 
98
                );
 
99
                $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
 
100
 
 
101
                // Path is prefixed with a "/"
 
102
                $this->options['dbname'] = substr($this->options['path'], 1);
 
103
 
 
104
                try
 
105
                {
 
106
                        $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'));
 
107
                }
 
108
                catch (PDOException $e)
 
109
                {
 
110
                        $this->mysql = null;
 
111
                        return;
 
112
                }
 
113
 
 
114
                $this->id = $name . $type;
 
115
 
 
116
                if (!$query = $this->mysql->query('SHOW TABLES'))
 
117
                {
 
118
                        $this->mysql = null;
 
119
                        return;
 
120
                }
 
121
 
 
122
                $db = array();
 
123
                while ($row = $query->fetchColumn())
 
124
                {
 
125
                        $db[] = $row;
 
126
                }
 
127
 
 
128
                if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
 
129
                {
 
130
                        $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)))');
 
131
                        if ($query === false)
 
132
                        {
 
133
                                $this->mysql = null;
 
134
                        }
 
135
                }
 
136
 
 
137
                if (!in_array($this->options['extras']['prefix'] . 'items', $db))
 
138
                {
 
139
                        $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` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
 
140
                        if ($query === false)
 
141
                        {
 
142
                                $this->mysql = null;
 
143
                        }
 
144
                }
 
145
        }
 
146
 
 
147
        /**
 
148
         * Save data to the cache
 
149
         *
 
150
         * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
 
151
         * @return bool Successfulness
 
152
         */
 
153
        public function save($data)
 
154
        {
 
155
                if ($this->mysql === null)
 
156
                {
 
157
                        return false;
 
158
                }
 
159
 
 
160
                if ($data instanceof SimplePie)
 
161
                {
 
162
                        $data = clone $data;
 
163
 
 
164
                        $prepared = self::prepare_simplepie_object_for_cache($data);
 
165
 
 
166
                        $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
 
167
                        $query->bindValue(':feed', $this->id);
 
168
                        if ($query->execute())
 
169
                        {
 
170
                                if ($query->fetchColumn() > 0)
 
171
                                {
 
172
                                        $items = count($prepared[1]);
 
173
                                        if ($items)
 
174
                                        {
 
175
                                                $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
 
176
                                                $query = $this->mysql->prepare($sql);
 
177
                                                $query->bindValue(':items', $items);
 
178
                                        }
 
179
                                        else
 
180
                                        {
 
181
                                                $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
 
182
                                                $query = $this->mysql->prepare($sql);
 
183
                                        }
 
184
 
 
185
                                        $query->bindValue(':data', $prepared[0]);
 
186
                                        $query->bindValue(':time', time());
 
187
                                        $query->bindValue(':feed', $this->id);
 
188
                                        if (!$query->execute())
 
189
                                        {
 
190
                                                return false;
 
191
                                        }
 
192
                                }
 
193
                                else
 
194
                                {
 
195
                                        $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
 
196
                                        $query->bindValue(':feed', $this->id);
 
197
                                        $query->bindValue(':count', count($prepared[1]));
 
198
                                        $query->bindValue(':data', $prepared[0]);
 
199
                                        $query->bindValue(':time', time());
 
200
                                        if (!$query->execute())
 
201
                                        {
 
202
                                                return false;
 
203
                                        }
 
204
                                }
 
205
 
 
206
                                $ids = array_keys($prepared[1]);
 
207
                                if (!empty($ids))
 
208
                                {
 
209
                                        foreach ($ids as $id)
 
210
                                        {
 
211
                                                $database_ids[] = $this->mysql->quote($id);
 
212
                                        }
 
213
 
 
214
                                        $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
 
215
                                        $query->bindValue(':feed', $this->id);
 
216
 
 
217
                                        if ($query->execute())
 
218
                                        {
 
219
                                                $existing_ids = array();
 
220
                                                while ($row = $query->fetchColumn())
 
221
                                                {
 
222
                                                        $existing_ids[] = $row;
 
223
                                                }
 
224
 
 
225
                                                $new_ids = array_diff($ids, $existing_ids);
 
226
 
 
227
                                                foreach ($new_ids as $new_id)
 
228
                                                {
 
229
                                                        if (!($date = $prepared[1][$new_id]->get_date('U')))
 
230
                                                        {
 
231
                                                                $date = time();
 
232
                                                        }
 
233
 
 
234
                                                        $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
 
235
                                                        $query->bindValue(':feed', $this->id);
 
236
                                                        $query->bindValue(':id', $new_id);
 
237
                                                        $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
 
238
                                                        $query->bindValue(':date', $date);
 
239
                                                        if (!$query->execute())
 
240
                                                        {
 
241
                                                                return false;
 
242
                                                        }
 
243
                                                }
 
244
                                                return true;
 
245
                                        }
 
246
                                }
 
247
                                else
 
248
                                {
 
249
                                        return true;
 
250
                                }
 
251
                        }
 
252
                }
 
253
                else
 
254
                {
 
255
                        $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
 
256
                        $query->bindValue(':feed', $this->id);
 
257
                        if ($query->execute())
 
258
                        {
 
259
                                if ($query->rowCount() > 0)
 
260
                                {
 
261
                                        $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
 
262
                                        $query->bindValue(':data', serialize($data));
 
263
                                        $query->bindValue(':time', time());
 
264
                                        $query->bindValue(':feed', $this->id);
 
265
                                        if ($this->execute())
 
266
                                        {
 
267
                                                return true;
 
268
                                        }
 
269
                                }
 
270
                                else
 
271
                                {
 
272
                                        $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
 
273
                                        $query->bindValue(':id', $this->id);
 
274
                                        $query->bindValue(':data', serialize($data));
 
275
                                        $query->bindValue(':time', time());
 
276
                                        if ($query->execute())
 
277
                                        {
 
278
                                                return true;
 
279
                                        }
 
280
                                }
 
281
                        }
 
282
                }
 
283
                return false;
 
284
        }
 
285
 
 
286
        /**
 
287
         * Retrieve the data saved to the cache
 
288
         *
 
289
         * @return array Data for SimplePie::$data
 
290
         */
 
291
        public function load()
 
292
        {
 
293
                if ($this->mysql === null)
 
294
                {
 
295
                        return false;
 
296
                }
 
297
 
 
298
                $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
 
299
                $query->bindValue(':id', $this->id);
 
300
                if ($query->execute() && ($row = $query->fetch()))
 
301
                {
 
302
                        $data = unserialize($row[1]);
 
303
 
 
304
                        if (isset($this->options['items'][0]))
 
305
                        {
 
306
                                $items = (int) $this->options['items'][0];
 
307
                        }
 
308
                        else
 
309
                        {
 
310
                                $items = (int) $row[0];
 
311
                        }
 
312
 
 
313
                        if ($items !== 0)
 
314
                        {
 
315
                                if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
 
316
                                {
 
317
                                        $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
 
318
                                }
 
319
                                elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
 
320
                                {
 
321
                                        $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
 
322
                                }
 
323
                                elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
 
324
                                {
 
325
                                        $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
 
326
                                }
 
327
                                elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
 
328
                                {
 
329
                                        $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
 
330
                                }
 
331
                                else
 
332
                                {
 
333
                                        $feed = null;
 
334
                                }
 
335
 
 
336
                                if ($feed !== null)
 
337
                                {
 
338
                                        $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
 
339
                                        if ($items > 0)
 
340
                                        {
 
341
                                                $sql .= ' LIMIT ' . $items;
 
342
                                        }
 
343
 
 
344
                                        $query = $this->mysql->prepare($sql);
 
345
                                        $query->bindValue(':feed', $this->id);
 
346
                                        if ($query->execute())
 
347
                                        {
 
348
                                                while ($row = $query->fetchColumn())
 
349
                                                {
 
350
                                                        $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
 
351
                                                }
 
352
                                        }
 
353
                                        else
 
354
                                        {
 
355
                                                return false;
 
356
                                        }
 
357
                                }
 
358
                        }
 
359
                        return $data;
 
360
                }
 
361
                return false;
 
362
        }
 
363
 
 
364
        /**
 
365
         * Retrieve the last modified time for the cache
 
366
         *
 
367
         * @return int Timestamp
 
368
         */
 
369
        public function mtime()
 
370
        {
 
371
                if ($this->mysql === null)
 
372
                {
 
373
                        return false;
 
374
                }
 
375
 
 
376
                $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
 
377
                $query->bindValue(':id', $this->id);
 
378
                if ($query->execute() && ($time = $query->fetchColumn()))
 
379
                {
 
380
                        return $time;
 
381
                }
 
382
                else
 
383
                {
 
384
                        return false;
 
385
                }
 
386
        }
 
387
 
 
388
        /**
 
389
         * Set the last modified time to the current time
 
390
         *
 
391
         * @return bool Success status
 
392
         */
 
393
        public function touch()
 
394
        {
 
395
                if ($this->mysql === null)
 
396
                {
 
397
                        return false;
 
398
                }
 
399
 
 
400
                $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
 
401
                $query->bindValue(':time', time());
 
402
                $query->bindValue(':id', $this->id);
 
403
                if ($query->execute() && $query->rowCount() > 0)
 
404
                {
 
405
                        return true;
 
406
                }
 
407
                else
 
408
                {
 
409
                        return false;
 
410
                }
 
411
        }
 
412
 
 
413
        /**
 
414
         * Remove the cache
 
415
         *
 
416
         * @return bool Success status
 
417
         */
 
418
        public function unlink()
 
419
        {
 
420
                if ($this->mysql === null)
 
421
                {
 
422
                        return false;
 
423
                }
 
424
 
 
425
                $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
 
426
                $query->bindValue(':id', $this->id);
 
427
                $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
 
428
                $query2->bindValue(':id', $this->id);
 
429
                if ($query->execute() && $query2->execute())
 
430
                {
 
431
                        return true;
 
432
                }
 
433
                else
 
434
                {
 
435
                        return false;
 
436
                }
 
437
        }
 
438
}