Projects : mp-wp : mp-wp_genesis
1 | <?php |
2 | /** |
3 | * MagpieRSS: a simple RSS integration tool |
4 | * |
5 | * A compiled file for RSS syndication |
6 | * |
7 | * @author Kellan Elliott-McCrea <kellan@protest.net> |
8 | * @version 0.51 |
9 | * @license GPL |
10 | * |
11 | * @package External |
12 | * @subpackage MagpieRSS |
13 | */ |
14 | |
15 | /* |
16 | * Hook to use another RSS object instead of MagpieRSS |
17 | */ |
18 | do_action('load_feed_engine'); |
19 | |
20 | /** RSS feed constant. */ |
21 | define('RSS', 'RSS'); |
22 | define('ATOM', 'Atom'); |
23 | define('MAGPIE_USER_AGENT', 'WordPress/' . $GLOBALS['wp_version']); |
24 | |
25 | class MagpieRSS { |
26 | var $parser; |
27 | var $current_item = array(); // item currently being parsed |
28 | var $items = array(); // collection of parsed items |
29 | var $channel = array(); // hash of channel fields |
30 | var $textinput = array(); |
31 | var $image = array(); |
32 | var $feed_type; |
33 | var $feed_version; |
34 | |
35 | // parser variables |
36 | var $stack = array(); // parser stack |
37 | var $inchannel = false; |
38 | var $initem = false; |
39 | var $incontent = false; // if in Atom <content mode="xml"> field |
40 | var $intextinput = false; |
41 | var $inimage = false; |
42 | var $current_field = ''; |
43 | var $current_namespace = false; |
44 | |
45 | //var $ERROR = ""; |
46 | |
47 | var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright'); |
48 | |
49 | function MagpieRSS ($source) { |
50 | |
51 | # if PHP xml isn't compiled in, die |
52 | # |
53 | if ( !function_exists('xml_parser_create') ) |
54 | trigger_error( "Failed to load PHP's XML Extension. http://www.php.net/manual/en/ref.xml.php" ); |
55 | |
56 | $parser = @xml_parser_create(); |
57 | |
58 | if ( !is_resource($parser) ) |
59 | trigger_error( "Failed to create an instance of PHP's XML parser. http://www.php.net/manual/en/ref.xml.php"); |
60 | |
61 | |
62 | $this->parser = $parser; |
63 | |
64 | # pass in parser, and a reference to this object |
65 | # setup handlers |
66 | # |
67 | xml_set_object( $this->parser, $this ); |
68 | xml_set_element_handler($this->parser, |
69 | 'feed_start_element', 'feed_end_element' ); |
70 | |
71 | xml_set_character_data_handler( $this->parser, 'feed_cdata' ); |
72 | |
73 | $status = xml_parse( $this->parser, $source ); |
74 | |
75 | if (! $status ) { |
76 | $errorcode = xml_get_error_code( $this->parser ); |
77 | if ( $errorcode != XML_ERROR_NONE ) { |
78 | $xml_error = xml_error_string( $errorcode ); |
79 | $error_line = xml_get_current_line_number($this->parser); |
80 | $error_col = xml_get_current_column_number($this->parser); |
81 | $errormsg = "$xml_error at line $error_line, column $error_col"; |
82 | |
83 | $this->error( $errormsg ); |
84 | } |
85 | } |
86 | |
87 | xml_parser_free( $this->parser ); |
88 | |
89 | $this->normalize(); |
90 | } |
91 | |
92 | function feed_start_element($p, $element, &$attrs) { |
93 | $el = $element = strtolower($element); |
94 | $attrs = array_change_key_case($attrs, CASE_LOWER); |
95 | |
96 | // check for a namespace, and split if found |
97 | $ns = false; |
98 | if ( strpos( $element, ':' ) ) { |
99 | list($ns, $el) = split( ':', $element, 2); |
100 | } |
101 | if ( $ns and $ns != 'rdf' ) { |
102 | $this->current_namespace = $ns; |
103 | } |
104 | |
105 | # if feed type isn't set, then this is first element of feed |
106 | # identify feed from root element |
107 | # |
108 | if (!isset($this->feed_type) ) { |
109 | if ( $el == 'rdf' ) { |
110 | $this->feed_type = RSS; |
111 | $this->feed_version = '1.0'; |
112 | } |
113 | elseif ( $el == 'rss' ) { |
114 | $this->feed_type = RSS; |
115 | $this->feed_version = $attrs['version']; |
116 | } |
117 | elseif ( $el == 'feed' ) { |
118 | $this->feed_type = ATOM; |
119 | $this->feed_version = $attrs['version']; |
120 | $this->inchannel = true; |
121 | } |
122 | return; |
123 | } |
124 | |
125 | if ( $el == 'channel' ) |
126 | { |
127 | $this->inchannel = true; |
128 | } |
129 | elseif ($el == 'item' or $el == 'entry' ) |
130 | { |
131 | $this->initem = true; |
132 | if ( isset($attrs['rdf:about']) ) { |
133 | $this->current_item['about'] = $attrs['rdf:about']; |
134 | } |
135 | } |
136 | |
137 | // if we're in the default namespace of an RSS feed, |
138 | // record textinput or image fields |
139 | elseif ( |
140 | $this->feed_type == RSS and |
141 | $this->current_namespace == '' and |
142 | $el == 'textinput' ) |
143 | { |
144 | $this->intextinput = true; |
145 | } |
146 | |
147 | elseif ( |
148 | $this->feed_type == RSS and |
149 | $this->current_namespace == '' and |
150 | $el == 'image' ) |
151 | { |
152 | $this->inimage = true; |
153 | } |
154 | |
155 | # handle atom content constructs |
156 | elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) |
157 | { |
158 | // avoid clashing w/ RSS mod_content |
159 | if ($el == 'content' ) { |
160 | $el = 'atom_content'; |
161 | } |
162 | |
163 | $this->incontent = $el; |
164 | |
165 | |
166 | } |
167 | |
168 | // if inside an Atom content construct (e.g. content or summary) field treat tags as text |
169 | elseif ($this->feed_type == ATOM and $this->incontent ) |
170 | { |
171 | // if tags are inlined, then flatten |
172 | $attrs_str = join(' ', |
173 | array_map('map_attrs', |
174 | array_keys($attrs), |
175 | array_values($attrs) ) ); |
176 | |
177 | $this->append_content( "<$element $attrs_str>" ); |
178 | |
179 | array_unshift( $this->stack, $el ); |
180 | } |
181 | |
182 | // Atom support many links per containging element. |
183 | // Magpie treats link elements of type rel='alternate' |
184 | // as being equivalent to RSS's simple link element. |
185 | // |
186 | elseif ($this->feed_type == ATOM and $el == 'link' ) |
187 | { |
188 | if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' ) |
189 | { |
190 | $link_el = 'link'; |
191 | } |
192 | else { |
193 | $link_el = 'link_' . $attrs['rel']; |
194 | } |
195 | |
196 | $this->append($link_el, $attrs['href']); |
197 | } |
198 | // set stack[0] to current element |
199 | else { |
200 | array_unshift($this->stack, $el); |
201 | } |
202 | } |
203 | |
204 | |
205 | |
206 | function feed_cdata ($p, $text) { |
207 | |
208 | if ($this->feed_type == ATOM and $this->incontent) |
209 | { |
210 | $this->append_content( $text ); |
211 | } |
212 | else { |
213 | $current_el = join('_', array_reverse($this->stack)); |
214 | $this->append($current_el, $text); |
215 | } |
216 | } |
217 | |
218 | function feed_end_element ($p, $el) { |
219 | $el = strtolower($el); |
220 | |
221 | if ( $el == 'item' or $el == 'entry' ) |
222 | { |
223 | $this->items[] = $this->current_item; |
224 | $this->current_item = array(); |
225 | $this->initem = false; |
226 | } |
227 | elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' ) |
228 | { |
229 | $this->intextinput = false; |
230 | } |
231 | elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' ) |
232 | { |
233 | $this->inimage = false; |
234 | } |
235 | elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) |
236 | { |
237 | $this->incontent = false; |
238 | } |
239 | elseif ($el == 'channel' or $el == 'feed' ) |
240 | { |
241 | $this->inchannel = false; |
242 | } |
243 | elseif ($this->feed_type == ATOM and $this->incontent ) { |
244 | // balance tags properly |
245 | // note: i don't think this is actually neccessary |
246 | if ( $this->stack[0] == $el ) |
247 | { |
248 | $this->append_content("</$el>"); |
249 | } |
250 | else { |
251 | $this->append_content("<$el />"); |
252 | } |
253 | |
254 | array_shift( $this->stack ); |
255 | } |
256 | else { |
257 | array_shift( $this->stack ); |
258 | } |
259 | |
260 | $this->current_namespace = false; |
261 | } |
262 | |
263 | function concat (&$str1, $str2="") { |
264 | if (!isset($str1) ) { |
265 | $str1=""; |
266 | } |
267 | $str1 .= $str2; |
268 | } |
269 | |
270 | function append_content($text) { |
271 | if ( $this->initem ) { |
272 | $this->concat( $this->current_item[ $this->incontent ], $text ); |
273 | } |
274 | elseif ( $this->inchannel ) { |
275 | $this->concat( $this->channel[ $this->incontent ], $text ); |
276 | } |
277 | } |
278 | |
279 | // smart append - field and namespace aware |
280 | function append($el, $text) { |
281 | if (!$el) { |
282 | return; |
283 | } |
284 | if ( $this->current_namespace ) |
285 | { |
286 | if ( $this->initem ) { |
287 | $this->concat( |
288 | $this->current_item[ $this->current_namespace ][ $el ], $text); |
289 | } |
290 | elseif ($this->inchannel) { |
291 | $this->concat( |
292 | $this->channel[ $this->current_namespace][ $el ], $text ); |
293 | } |
294 | elseif ($this->intextinput) { |
295 | $this->concat( |
296 | $this->textinput[ $this->current_namespace][ $el ], $text ); |
297 | } |
298 | elseif ($this->inimage) { |
299 | $this->concat( |
300 | $this->image[ $this->current_namespace ][ $el ], $text ); |
301 | } |
302 | } |
303 | else { |
304 | if ( $this->initem ) { |
305 | $this->concat( |
306 | $this->current_item[ $el ], $text); |
307 | } |
308 | elseif ($this->intextinput) { |
309 | $this->concat( |
310 | $this->textinput[ $el ], $text ); |
311 | } |
312 | elseif ($this->inimage) { |
313 | $this->concat( |
314 | $this->image[ $el ], $text ); |
315 | } |
316 | elseif ($this->inchannel) { |
317 | $this->concat( |
318 | $this->channel[ $el ], $text ); |
319 | } |
320 | |
321 | } |
322 | } |
323 | |
324 | function normalize () { |
325 | // if atom populate rss fields |
326 | if ( $this->is_atom() ) { |
327 | $this->channel['descripton'] = $this->channel['tagline']; |
328 | for ( $i = 0; $i < count($this->items); $i++) { |
329 | $item = $this->items[$i]; |
330 | if ( isset($item['summary']) ) |
331 | $item['description'] = $item['summary']; |
332 | if ( isset($item['atom_content'])) |
333 | $item['content']['encoded'] = $item['atom_content']; |
334 | |
335 | $this->items[$i] = $item; |
336 | } |
337 | } |
338 | elseif ( $this->is_rss() ) { |
339 | $this->channel['tagline'] = $this->channel['description']; |
340 | for ( $i = 0; $i < count($this->items); $i++) { |
341 | $item = $this->items[$i]; |
342 | if ( isset($item['description'])) |
343 | $item['summary'] = $item['description']; |
344 | if ( isset($item['content']['encoded'] ) ) |
345 | $item['atom_content'] = $item['content']['encoded']; |
346 | |
347 | $this->items[$i] = $item; |
348 | } |
349 | } |
350 | } |
351 | |
352 | function is_rss () { |
353 | if ( $this->feed_type == RSS ) { |
354 | return $this->feed_version; |
355 | } |
356 | else { |
357 | return false; |
358 | } |
359 | } |
360 | |
361 | function is_atom() { |
362 | if ( $this->feed_type == ATOM ) { |
363 | return $this->feed_version; |
364 | } |
365 | else { |
366 | return false; |
367 | } |
368 | } |
369 | |
370 | function map_attrs($k, $v) { |
371 | return "$k=\"$v\""; |
372 | } |
373 | |
374 | function error( $errormsg, $lvl = E_USER_WARNING ) { |
375 | // append PHP's error message if track_errors enabled |
376 | if ( isset($php_errormsg) ) { |
377 | $errormsg .= " ($php_errormsg)"; |
378 | } |
379 | if ( MAGPIE_DEBUG ) { |
380 | trigger_error( $errormsg, $lvl); |
381 | } else { |
382 | error_log( $errormsg, 0); |
383 | } |
384 | } |
385 | |
386 | } |
387 | |
388 | if ( !function_exists('fetch_rss') ) : |
389 | /** |
390 | * Build Magpie object based on RSS from URL. |
391 | * |
392 | * @since unknown |
393 | * @package External |
394 | * @subpackage MagpieRSS |
395 | * |
396 | * @param string $url URL to retrieve feed |
397 | * @return bool|MagpieRSS false on failure or MagpieRSS object on success. |
398 | */ |
399 | function fetch_rss ($url) { |
400 | // initialize constants |
401 | init(); |
402 | |
403 | if ( !isset($url) ) { |
404 | // error("fetch_rss called without a url"); |
405 | return false; |
406 | } |
407 | |
408 | // if cache is disabled |
409 | if ( !MAGPIE_CACHE_ON ) { |
410 | // fetch file, and parse it |
411 | $resp = _fetch_remote_file( $url ); |
412 | if ( is_success( $resp->status ) ) { |
413 | return _response_to_rss( $resp ); |
414 | } |
415 | else { |
416 | // error("Failed to fetch $url and cache is off"); |
417 | return false; |
418 | } |
419 | } |
420 | // else cache is ON |
421 | else { |
422 | // Flow |
423 | // 1. check cache |
424 | // 2. if there is a hit, make sure its fresh |
425 | // 3. if cached obj fails freshness check, fetch remote |
426 | // 4. if remote fails, return stale object, or error |
427 | |
428 | $cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE ); |
429 | |
430 | if (MAGPIE_DEBUG and $cache->ERROR) { |
431 | debug($cache->ERROR, E_USER_WARNING); |
432 | } |
433 | |
434 | |
435 | $cache_status = 0; // response of check_cache |
436 | $request_headers = array(); // HTTP headers to send with fetch |
437 | $rss = 0; // parsed RSS object |
438 | $errormsg = 0; // errors, if any |
439 | |
440 | if (!$cache->ERROR) { |
441 | // return cache HIT, MISS, or STALE |
442 | $cache_status = $cache->check_cache( $url ); |
443 | } |
444 | |
445 | // if object cached, and cache is fresh, return cached obj |
446 | if ( $cache_status == 'HIT' ) { |
447 | $rss = $cache->get( $url ); |
448 | if ( isset($rss) and $rss ) { |
449 | $rss->from_cache = 1; |
450 | if ( MAGPIE_DEBUG > 1) { |
451 | debug("MagpieRSS: Cache HIT", E_USER_NOTICE); |
452 | } |
453 | return $rss; |
454 | } |
455 | } |
456 | |
457 | // else attempt a conditional get |
458 | |
459 | // setup headers |
460 | if ( $cache_status == 'STALE' ) { |
461 | $rss = $cache->get( $url ); |
462 | if ( isset($rss->etag) and $rss->last_modified ) { |
463 | $request_headers['If-None-Match'] = $rss->etag; |
464 | $request_headers['If-Last-Modified'] = $rss->last_modified; |
465 | } |
466 | } |
467 | |
468 | $resp = _fetch_remote_file( $url, $request_headers ); |
469 | |
470 | if (isset($resp) and $resp) { |
471 | if ($resp->status == '304' ) { |
472 | // we have the most current copy |
473 | if ( MAGPIE_DEBUG > 1) { |
474 | debug("Got 304 for $url"); |
475 | } |
476 | // reset cache on 304 (at minutillo insistent prodding) |
477 | $cache->set($url, $rss); |
478 | return $rss; |
479 | } |
480 | elseif ( is_success( $resp->status ) ) { |
481 | $rss = _response_to_rss( $resp ); |
482 | if ( $rss ) { |
483 | if (MAGPIE_DEBUG > 1) { |
484 | debug("Fetch successful"); |
485 | } |
486 | // add object to cache |
487 | $cache->set( $url, $rss ); |
488 | return $rss; |
489 | } |
490 | } |
491 | else { |
492 | $errormsg = "Failed to fetch $url. "; |
493 | if ( $resp->error ) { |
494 | # compensate for Snoopy's annoying habbit to tacking |
495 | # on '\n' |
496 | $http_error = substr($resp->error, 0, -2); |
497 | $errormsg .= "(HTTP Error: $http_error)"; |
498 | } |
499 | else { |
500 | $errormsg .= "(HTTP Response: " . $resp->response_code .')'; |
501 | } |
502 | } |
503 | } |
504 | else { |
505 | $errormsg = "Unable to retrieve RSS file for unknown reasons."; |
506 | } |
507 | |
508 | // else fetch failed |
509 | |
510 | // attempt to return cached object |
511 | if ($rss) { |
512 | if ( MAGPIE_DEBUG ) { |
513 | debug("Returning STALE object for $url"); |
514 | } |
515 | return $rss; |
516 | } |
517 | |
518 | // else we totally failed |
519 | // error( $errormsg ); |
520 | |
521 | return false; |
522 | |
523 | } // end if ( !MAGPIE_CACHE_ON ) { |
524 | } // end fetch_rss() |
525 | endif; |
526 | |
527 | /** |
528 | * Retrieve URL headers and content using WP HTTP Request API. |
529 | * |
530 | * @since unknown |
531 | * @package External |
532 | * @subpackage MagpieRSS |
533 | * |
534 | * @param string $url URL to retrieve |
535 | * @param array $headers Optional. Headers to send to the URL. |
536 | * @return Snoopy style response |
537 | */ |
538 | function _fetch_remote_file ($url, $headers = "" ) { |
539 | $resp = wp_remote_request($url, array('headers' => $headers, 'timeout' => MAGPIE_FETCH_TIME_OUT)); |
540 | if ( is_wp_error($resp) ) { |
541 | $error = array_shift($resp->errors); |
542 | |
543 | $resp = new stdClass; |
544 | $resp->status = 500; |
545 | $resp->response_code = 500; |
546 | $resp->error = $error[0] . "\n"; //\n = Snoopy compatibility |
547 | return $resp; |
548 | } |
549 | $response = new stdClass; |
550 | $response->status = $resp['response']['code']; |
551 | $response->response_code = $resp['response']['code']; |
552 | $response->headers = $resp['headers']; |
553 | $response->results = $resp['body']; |
554 | |
555 | return $response; |
556 | } |
557 | |
558 | /** |
559 | * Retrieve |
560 | * |
561 | * @since unknown |
562 | * @package External |
563 | * @subpackage MagpieRSS |
564 | * |
565 | * @param unknown_type $resp |
566 | * @return unknown |
567 | */ |
568 | function _response_to_rss ($resp) { |
569 | $rss = new MagpieRSS( $resp->results ); |
570 | |
571 | // if RSS parsed successfully |
572 | if ( $rss && (!isset($rss->ERROR) || !$rss->ERROR) ) { |
573 | |
574 | // find Etag, and Last-Modified |
575 | foreach( (array) $resp->headers as $h) { |
576 | // 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1" |
577 | if (strpos($h, ": ")) { |
578 | list($field, $val) = explode(": ", $h, 2); |
579 | } |
580 | else { |
581 | $field = $h; |
582 | $val = ""; |
583 | } |
584 | |
585 | if ( $field == 'ETag' ) { |
586 | $rss->etag = $val; |
587 | } |
588 | |
589 | if ( $field == 'Last-Modified' ) { |
590 | $rss->last_modified = $val; |
591 | } |
592 | } |
593 | |
594 | return $rss; |
595 | } // else construct error message |
596 | else { |
597 | $errormsg = "Failed to parse RSS file."; |
598 | |
599 | if ($rss) { |
600 | $errormsg .= " (" . $rss->ERROR . ")"; |
601 | } |
602 | // error($errormsg); |
603 | |
604 | return false; |
605 | } // end if ($rss and !$rss->error) |
606 | } |
607 | |
608 | /** |
609 | * Setup constants with default values, unless user overrides. |
610 | * |
611 | * @since unknown |
612 | * @package External |
613 | * @subpackage MagpieRSS |
614 | */ |
615 | function init () { |
616 | if ( defined('MAGPIE_INITALIZED') ) { |
617 | return; |
618 | } |
619 | else { |
620 | define('MAGPIE_INITALIZED', 1); |
621 | } |
622 | |
623 | if ( !defined('MAGPIE_CACHE_ON') ) { |
624 | define('MAGPIE_CACHE_ON', 1); |
625 | } |
626 | |
627 | if ( !defined('MAGPIE_CACHE_DIR') ) { |
628 | define('MAGPIE_CACHE_DIR', './cache'); |
629 | } |
630 | |
631 | if ( !defined('MAGPIE_CACHE_AGE') ) { |
632 | define('MAGPIE_CACHE_AGE', 60*60); // one hour |
633 | } |
634 | |
635 | if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) { |
636 | define('MAGPIE_CACHE_FRESH_ONLY', 0); |
637 | } |
638 | |
639 | if ( !defined('MAGPIE_DEBUG') ) { |
640 | define('MAGPIE_DEBUG', 0); |
641 | } |
642 | |
643 | if ( !defined('MAGPIE_USER_AGENT') ) { |
644 | $ua = 'WordPress/' . $GLOBALS['wp_version']; |
645 | |
646 | if ( MAGPIE_CACHE_ON ) { |
647 | $ua = $ua . ')'; |
648 | } |
649 | else { |
650 | $ua = $ua . '; No cache)'; |
651 | } |
652 | |
653 | define('MAGPIE_USER_AGENT', $ua); |
654 | } |
655 | |
656 | if ( !defined('MAGPIE_FETCH_TIME_OUT') ) { |
657 | define('MAGPIE_FETCH_TIME_OUT', 2); // 2 second timeout |
658 | } |
659 | |
660 | // use gzip encoding to fetch rss files if supported? |
661 | if ( !defined('MAGPIE_USE_GZIP') ) { |
662 | define('MAGPIE_USE_GZIP', true); |
663 | } |
664 | } |
665 | |
666 | function is_info ($sc) { |
667 | return $sc >= 100 && $sc < 200; |
668 | } |
669 | |
670 | function is_success ($sc) { |
671 | return $sc >= 200 && $sc < 300; |
672 | } |
673 | |
674 | function is_redirect ($sc) { |
675 | return $sc >= 300 && $sc < 400; |
676 | } |
677 | |
678 | function is_error ($sc) { |
679 | return $sc >= 400 && $sc < 600; |
680 | } |
681 | |
682 | function is_client_error ($sc) { |
683 | return $sc >= 400 && $sc < 500; |
684 | } |
685 | |
686 | function is_server_error ($sc) { |
687 | return $sc >= 500 && $sc < 600; |
688 | } |
689 | |
690 | class RSSCache { |
691 | var $BASE_CACHE; // where the cache files are stored |
692 | var $MAX_AGE = 43200; // when are files stale, default twelve hours |
693 | var $ERROR = ''; // accumulate error messages |
694 | |
695 | function RSSCache ($base='', $age='') { |
696 | $this->BASE_CACHE = WP_CONTENT_DIR . '/cache'; |
697 | if ( $base ) { |
698 | $this->BASE_CACHE = $base; |
699 | } |
700 | if ( $age ) { |
701 | $this->MAX_AGE = $age; |
702 | } |
703 | |
704 | } |
705 | |
706 | /*=======================================================================*\ |
707 | Function: set |
708 | Purpose: add an item to the cache, keyed on url |
709 | Input: url from wich the rss file was fetched |
710 | Output: true on sucess |
711 | \*=======================================================================*/ |
712 | function set ($url, $rss) { |
713 | global $wpdb; |
714 | $cache_option = 'rss_' . $this->file_name( $url ); |
715 | $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts'; |
716 | |
717 | // shouldn't these be using get_option() ? |
718 | if ( !$wpdb->get_var( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name = %s", $cache_option ) ) ) |
719 | add_option($cache_option, '', '', 'no'); |
720 | if ( !$wpdb->get_var( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name = %s", $cache_timestamp ) ) ) |
721 | add_option($cache_timestamp, '', '', 'no'); |
722 | |
723 | update_option($cache_option, $rss); |
724 | update_option($cache_timestamp, time() ); |
725 | |
726 | return $cache_option; |
727 | } |
728 | |
729 | /*=======================================================================*\ |
730 | Function: get |
731 | Purpose: fetch an item from the cache |
732 | Input: url from wich the rss file was fetched |
733 | Output: cached object on HIT, false on MISS |
734 | \*=======================================================================*/ |
735 | function get ($url) { |
736 | $this->ERROR = ""; |
737 | $cache_option = 'rss_' . $this->file_name( $url ); |
738 | |
739 | if ( ! get_option( $cache_option ) ) { |
740 | $this->debug( |
741 | "Cache doesn't contain: $url (cache option: $cache_option)" |
742 | ); |
743 | return 0; |
744 | } |
745 | |
746 | $rss = get_option( $cache_option ); |
747 | |
748 | return $rss; |
749 | } |
750 | |
751 | /*=======================================================================*\ |
752 | Function: check_cache |
753 | Purpose: check a url for membership in the cache |
754 | and whether the object is older then MAX_AGE (ie. STALE) |
755 | Input: url from wich the rss file was fetched |
756 | Output: cached object on HIT, false on MISS |
757 | \*=======================================================================*/ |
758 | function check_cache ( $url ) { |
759 | $this->ERROR = ""; |
760 | $cache_option = $this->file_name( $url ); |
761 | $cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts'; |
762 | |
763 | if ( $mtime = get_option($cache_timestamp) ) { |
764 | // find how long ago the file was added to the cache |
765 | // and whether that is longer then MAX_AGE |
766 | $age = time() - $mtime; |
767 | if ( $this->MAX_AGE > $age ) { |
768 | // object exists and is current |
769 | return 'HIT'; |
770 | } |
771 | else { |
772 | // object exists but is old |
773 | return 'STALE'; |
774 | } |
775 | } |
776 | else { |
777 | // object does not exist |
778 | return 'MISS'; |
779 | } |
780 | } |
781 | |
782 | /*=======================================================================*\ |
783 | Function: serialize |
784 | \*=======================================================================*/ |
785 | function serialize ( $rss ) { |
786 | return serialize( $rss ); |
787 | } |
788 | |
789 | /*=======================================================================*\ |
790 | Function: unserialize |
791 | \*=======================================================================*/ |
792 | function unserialize ( $data ) { |
793 | return unserialize( $data ); |
794 | } |
795 | |
796 | /*=======================================================================*\ |
797 | Function: file_name |
798 | Purpose: map url to location in cache |
799 | Input: url from wich the rss file was fetched |
800 | Output: a file name |
801 | \*=======================================================================*/ |
802 | function file_name ($url) { |
803 | return md5( $url ); |
804 | } |
805 | |
806 | /*=======================================================================*\ |
807 | Function: error |
808 | Purpose: register error |
809 | \*=======================================================================*/ |
810 | function error ($errormsg, $lvl=E_USER_WARNING) { |
811 | // append PHP's error message if track_errors enabled |
812 | if ( isset($php_errormsg) ) { |
813 | $errormsg .= " ($php_errormsg)"; |
814 | } |
815 | $this->ERROR = $errormsg; |
816 | if ( MAGPIE_DEBUG ) { |
817 | trigger_error( $errormsg, $lvl); |
818 | } |
819 | else { |
820 | error_log( $errormsg, 0); |
821 | } |
822 | } |
823 | function debug ($debugmsg, $lvl=E_USER_NOTICE) { |
824 | if ( MAGPIE_DEBUG ) { |
825 | $this->error("MagpieRSS [debug] $debugmsg", $lvl); |
826 | } |
827 | } |
828 | } |
829 | |
830 | if ( !function_exists('parse_w3cdtf') ) : |
831 | function parse_w3cdtf ( $date_str ) { |
832 | |
833 | # regex to match wc3dtf |
834 | $pat = "/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/"; |
835 | |
836 | if ( preg_match( $pat, $date_str, $match ) ) { |
837 | list( $year, $month, $day, $hours, $minutes, $seconds) = |
838 | array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[7]); |
839 | |
840 | # calc epoch for current date assuming GMT |
841 | $epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year); |
842 | |
843 | $offset = 0; |
844 | if ( $match[11] == 'Z' ) { |
845 | # zulu time, aka GMT |
846 | } |
847 | else { |
848 | list( $tz_mod, $tz_hour, $tz_min ) = |
849 | array( $match[8], $match[9], $match[10]); |
850 | |
851 | # zero out the variables |
852 | if ( ! $tz_hour ) { $tz_hour = 0; } |
853 | if ( ! $tz_min ) { $tz_min = 0; } |
854 | |
855 | $offset_secs = (($tz_hour*60)+$tz_min)*60; |
856 | |
857 | # is timezone ahead of GMT? then subtract offset |
858 | # |
859 | if ( $tz_mod == '+' ) { |
860 | $offset_secs = $offset_secs * -1; |
861 | } |
862 | |
863 | $offset = $offset_secs; |
864 | } |
865 | $epoch = $epoch + $offset; |
866 | return $epoch; |
867 | } |
868 | else { |
869 | return -1; |
870 | } |
871 | } |
872 | endif; |
873 | |
874 | if ( !function_exists('wp_rss') ) : |
875 | /** |
876 | * Display all RSS items in a HTML ordered list. |
877 | * |
878 | * @since unknown |
879 | * @package External |
880 | * @subpackage MagpieRSS |
881 | * |
882 | * @param string $url URL of feed to display. Will not auto sense feed URL. |
883 | * @param int $num_items Optional. Number of items to display, default is all. |
884 | */ |
885 | function wp_rss( $url, $num_items = -1 ) { |
886 | if ( $rss = fetch_rss( $url ) ) { |
887 | echo '<ul>'; |
888 | |
889 | if ( $num_items !== -1 ) { |
890 | $rss->items = array_slice( $rss->items, 0, $num_items ); |
891 | } |
892 | |
893 | foreach ( (array) $rss->items as $item ) { |
894 | printf( |
895 | '<li><a href="%1$s" title="%2$s">%3$s</a></li>', |
896 | clean_url( $item['link'] ), |
897 | attribute_escape( strip_tags( $item['description'] ) ), |
898 | htmlentities( $item['title'] ) |
899 | ); |
900 | } |
901 | |
902 | echo '</ul>'; |
903 | } else { |
904 | _e( 'An error has occurred, which probably means the feed is down. Try again later.' ); |
905 | } |
906 | } |
907 | endif; |
908 | |
909 | if ( !function_exists('get_rss') ) : |
910 | /** |
911 | * Display RSS items in HTML list items. |
912 | * |
913 | * You have to specify which HTML list you want, either ordered or unordered |
914 | * before using the function. You also have to specify how many items you wish |
915 | * to display. You can't display all of them like you can with wp_rss() |
916 | * function. |
917 | * |
918 | * @since unknown |
919 | * @package External |
920 | * @subpackage MagpieRSS |
921 | * |
922 | * @param string $url URL of feed to display. Will not auto sense feed URL. |
923 | * @param int $num_items Optional. Number of items to display, default is all. |
924 | * @return bool False on failure. |
925 | */ |
926 | function get_rss ($url, $num_items = 5) { // Like get posts, but for RSS |
927 | $rss = fetch_rss($url); |
928 | if ( $rss ) { |
929 | $rss->items = array_slice($rss->items, 0, $num_items); |
930 | foreach ( (array) $rss->items as $item ) { |
931 | echo "<li>\n"; |
932 | echo "<a href='$item[link]' title='$item[description]'>"; |
933 | echo htmlentities($item['title']); |
934 | echo "</a><br />\n"; |
935 | echo "</li>\n"; |
936 | } |
937 | } else { |
938 | return false; |
939 | } |
940 | } |
941 | endif; |
942 | |
943 | ?> |