1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:
44:
45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
56: class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
57: {
58: 59: 60: 61: 62:
63: protected $mysql;
64:
65: 66: 67: 68: 69:
70: protected $options;
71:
72: 73: 74: 75: 76:
77: protected $id;
78:
79: 80: 81: 82: 83: 84: 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: ),
97: );
98: $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
99:
100:
101: $this->options['dbname'] = substr($this->options['path'], 1);
102:
103: try
104: {
105: $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'));
106: }
107: catch (PDOException $e)
108: {
109: $this->mysql = null;
110: return;
111: }
112:
113: $this->id = $name . $type;
114:
115: if (!$query = $this->mysql->query('SHOW TABLES'))
116: {
117: $this->mysql = null;
118: return;
119: }
120:
121: $db = array();
122: while ($row = $query->fetchColumn())
123: {
124: $db[] = $row;
125: }
126:
127: if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
128: {
129: $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)))');
130: if ($query === false)
131: {
132: $this->mysql = null;
133: }
134: }
135:
136: if (!in_array($this->options['extras']['prefix'] . 'items', $db))
137: {
138: $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)))');
139: if ($query === false)
140: {
141: $this->mysql = null;
142: }
143: }
144: }
145:
146: 147: 148: 149: 150: 151:
152: public function save($data)
153: {
154: if ($this->mysql === null)
155: {
156: return false;
157: }
158:
159: if ($data instanceof SimplePie)
160: {
161: $data = clone $data;
162:
163: $prepared = self::prepare_simplepie_object_for_cache($data);
164:
165: $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
166: $query->bindValue(':feed', $this->id);
167: if ($query->execute())
168: {
169: if ($query->fetchColumn() > 0)
170: {
171: $items = count($prepared[1]);
172: if ($items)
173: {
174: $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
175: $query = $this->mysql->prepare($sql);
176: $query->bindValue(':items', $items);
177: }
178: else
179: {
180: $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
181: $query = $this->mysql->prepare($sql);
182: }
183:
184: $query->bindValue(':data', $prepared[0]);
185: $query->bindValue(':time', time());
186: $query->bindValue(':feed', $this->id);
187: if (!$query->execute())
188: {
189: return false;
190: }
191: }
192: else
193: {
194: $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
195: $query->bindValue(':feed', $this->id);
196: $query->bindValue(':count', count($prepared[1]));
197: $query->bindValue(':data', $prepared[0]);
198: $query->bindValue(':time', time());
199: if (!$query->execute())
200: {
201: return false;
202: }
203: }
204:
205: $ids = array_keys($prepared[1]);
206: if (!empty($ids))
207: {
208: foreach ($ids as $id)
209: {
210: $database_ids[] = $this->mysql->quote($id);
211: }
212:
213: $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
214: $query->bindValue(':feed', $this->id);
215:
216: if ($query->execute())
217: {
218: $existing_ids = array();
219: while ($row = $query->fetchColumn())
220: {
221: $existing_ids[] = $row;
222: }
223:
224: $new_ids = array_diff($ids, $existing_ids);
225:
226: foreach ($new_ids as $new_id)
227: {
228: if (!($date = $prepared[1][$new_id]->get_date('U')))
229: {
230: $date = time();
231: }
232:
233: $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
234: $query->bindValue(':feed', $this->id);
235: $query->bindValue(':id', $new_id);
236: $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
237: $query->bindValue(':date', $date);
238: if (!$query->execute())
239: {
240: return false;
241: }
242: }
243: return true;
244: }
245: }
246: else
247: {
248: return true;
249: }
250: }
251: }
252: else
253: {
254: $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
255: $query->bindValue(':feed', $this->id);
256: if ($query->execute())
257: {
258: if ($query->rowCount() > 0)
259: {
260: $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
261: $query->bindValue(':data', serialize($data));
262: $query->bindValue(':time', time());
263: $query->bindValue(':feed', $this->id);
264: if ($this->execute())
265: {
266: return true;
267: }
268: }
269: else
270: {
271: $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
272: $query->bindValue(':id', $this->id);
273: $query->bindValue(':data', serialize($data));
274: $query->bindValue(':time', time());
275: if ($query->execute())
276: {
277: return true;
278: }
279: }
280: }
281: }
282: return false;
283: }
284:
285: 286: 287: 288: 289:
290: public function load()
291: {
292: if ($this->mysql === null)
293: {
294: return false;
295: }
296:
297: $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
298: $query->bindValue(':id', $this->id);
299: if ($query->execute() && ($row = $query->fetch()))
300: {
301: $data = unserialize($row[1]);
302:
303: if (isset($this->options['items'][0]))
304: {
305: $items = (int) $this->options['items'][0];
306: }
307: else
308: {
309: $items = (int) $row[0];
310: }
311:
312: if ($items !== 0)
313: {
314: if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
315: {
316: $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
317: }
318: elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
319: {
320: $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
321: }
322: elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
323: {
324: $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
325: }
326: elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
327: {
328: $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
329: }
330: else
331: {
332: $feed = null;
333: }
334:
335: if ($feed !== null)
336: {
337: $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
338: if ($items > 0)
339: {
340: $sql .= ' LIMIT ' . $items;
341: }
342:
343: $query = $this->mysql->prepare($sql);
344: $query->bindValue(':feed', $this->id);
345: if ($query->execute())
346: {
347: while ($row = $query->fetchColumn())
348: {
349: $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
350: }
351: }
352: else
353: {
354: return false;
355: }
356: }
357: }
358: return $data;
359: }
360: return false;
361: }
362:
363: 364: 365: 366: 367:
368: public function mtime()
369: {
370: if ($this->mysql === null)
371: {
372: return false;
373: }
374:
375: $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
376: $query->bindValue(':id', $this->id);
377: if ($query->execute() && ($time = $query->fetchColumn()))
378: {
379: return $time;
380: }
381: else
382: {
383: return false;
384: }
385: }
386:
387: 388: 389: 390: 391:
392: public function touch()
393: {
394: if ($this->mysql === null)
395: {
396: return false;
397: }
398:
399: $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
400: $query->bindValue(':time', time());
401: $query->bindValue(':id', $this->id);
402: if ($query->execute() && $query->rowCount() > 0)
403: {
404: return true;
405: }
406: else
407: {
408: return false;
409: }
410: }
411:
412: 413: 414: 415: 416:
417: public function unlink()
418: {
419: if ($this->mysql === null)
420: {
421: return false;
422: }
423:
424: $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
425: $query->bindValue(':id', $this->id);
426: $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
427: $query2->bindValue(':id', $this->id);
428: if ($query->execute() && $query2->execute())
429: {
430: return true;
431: }
432: else
433: {
434: return false;
435: }
436: }
437: }
438: