/wp-includes/rss.php

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