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