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:
57: class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
58: {
59: 60: 61: 62: 63:
64: protected $mysql;
65:
66: 67: 68: 69: 70:
71: protected $options;
72:
73: 74: 75: 76: 77:
78: protected $id;
79:
80: 81: 82: 83: 84: 85: 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:
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: 149: 150: 151: 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: 288: 289: 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: 366: 367: 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: 390: 391: 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: 415: 416: 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: }
439: