PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/rss.php

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