MagpieRSS

The WordPress Core MagpieRSS class.

Defined (1)

The class is defined in the following location(s).

/wp-includes/rss.php  
  1. class MagpieRSS { 
  2. var $parser; 
  3. var $current_item = array(); // item currently being parsed 
  4. var $items = array(); // collection of parsed items 
  5. var $channel = array(); // hash of channel fields 
  6. var $textinput = array(); 
  7. var $image = array(); 
  8. var $feed_type; 
  9. var $feed_version; 
  10.  
  11. // parser variables 
  12. var $stack = array(); // parser stack 
  13. var $inchannel = false; 
  14. var $initem = false; 
  15. var $incontent = false; // if in Atom <content mode="xml"> field 
  16. var $intextinput = false; 
  17. var $inimage = false; 
  18. var $current_field = ''; 
  19. var $current_namespace = false; 
  20.  
  21. //var $ERROR = ""; 
  22.  
  23. var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright'); 
  24.  
  25. /** 
  26. * PHP5 constructor. 
  27. */ 
  28. function __construct( $source ) { 
  29.  
  30. # Check if PHP xml isn't compiled 
  31. if ( ! function_exists('xml_parser_create') ) { 
  32. return trigger_error( "PHP's XML extension is not available. Please contact your hosting provider to enable PHP's XML extension." ); 
  33.  
  34. $parser = xml_parser_create(); 
  35.  
  36. $this->parser = $parser; 
  37.  
  38. # pass in parser, and a reference to this object 
  39. # set up handlers 
  40. xml_set_object( $this->parser, $this ); 
  41. xml_set_element_handler($this->parser,  
  42. 'feed_start_element', 'feed_end_element' ); 
  43.  
  44. xml_set_character_data_handler( $this->parser, 'feed_cdata' ); 
  45.  
  46. $status = xml_parse( $this->parser, $source ); 
  47.  
  48. if (! $status ) { 
  49. $errorcode = xml_get_error_code( $this->parser ); 
  50. if ( $errorcode != XML_ERROR_NONE ) { 
  51. $xml_error = xml_error_string( $errorcode ); 
  52. $error_line = xml_get_current_line_number($this->parser); 
  53. $error_col = xml_get_current_column_number($this->parser); 
  54. $errormsg = "$xml_error at line $error_line, column $error_col"; 
  55.  
  56. $this->error( $errormsg ); 
  57.  
  58. xml_parser_free( $this->parser ); 
  59.  
  60. $this->normalize(); 
  61.  
  62. /** 
  63. * PHP4 constructor. 
  64. */ 
  65. public function MagpieRSS( $source ) { 
  66. self::__construct( $source ); 
  67.  
  68. function feed_start_element($p, $element, &$attrs) { 
  69. $el = $element = strtolower($element); 
  70. $attrs = array_change_key_case($attrs, CASE_LOWER); 
  71.  
  72. // check for a namespace, and split if found 
  73. $ns = false; 
  74. if ( strpos( $element, ':' ) ) { 
  75. list($ns, $el) = explode( ':', $element, 2); 
  76. if ( $ns and $ns != 'rdf' ) { 
  77. $this->current_namespace = $ns; 
  78.  
  79. # if feed type isn't set, then this is first element of feed 
  80. # identify feed from root element 
  81. if (!isset($this->feed_type) ) { 
  82. if ( $el == 'rdf' ) { 
  83. $this->feed_type = RSS; 
  84. $this->feed_version = '1.0'; 
  85. elseif ( $el == 'rss' ) { 
  86. $this->feed_type = RSS; 
  87. $this->feed_version = $attrs['version']; 
  88. elseif ( $el == 'feed' ) { 
  89. $this->feed_type = ATOM; 
  90. $this->feed_version = $attrs['version']; 
  91. $this->inchannel = true; 
  92. return; 
  93.  
  94. if ( $el == 'channel' ) 
  95. $this->inchannel = true; 
  96. elseif ($el == 'item' or $el == 'entry' ) 
  97. $this->initem = true; 
  98. if ( isset($attrs['rdf:about']) ) { 
  99. $this->current_item['about'] = $attrs['rdf:about']; 
  100.  
  101. // if we're in the default namespace of an RSS feed,  
  102. // record textinput or image fields 
  103. elseif ( 
  104. $this->feed_type == RSS and 
  105. $this->current_namespace == '' and 
  106. $el == 'textinput' ) 
  107. $this->intextinput = true; 
  108.  
  109. elseif ( 
  110. $this->feed_type == RSS and 
  111. $this->current_namespace == '' and 
  112. $el == 'image' ) 
  113. $this->inimage = true; 
  114.  
  115. # handle atom content constructs 
  116. elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) 
  117. // avoid clashing w/ RSS mod_content 
  118. if ($el == 'content' ) { 
  119. $el = 'atom_content'; 
  120.  
  121. $this->incontent = $el; 
  122.  
  123.  
  124. // if inside an Atom content construct (e.g. content or summary) field treat tags as text 
  125. elseif ($this->feed_type == ATOM and $this->incontent ) 
  126. // if tags are inlined, then flatten 
  127. $attrs_str = join(' ',  
  128. array_map(array('MagpieRSS', 'map_attrs'),  
  129. array_keys($attrs),  
  130. array_values($attrs) ) ); 
  131.  
  132. $this->append_content( "<$element $attrs_str>" ); 
  133.  
  134. array_unshift( $this->stack, $el ); 
  135.  
  136. // Atom support many links per containging element. 
  137. // Magpie treats link elements of type rel='alternate' 
  138. // as being equivalent to RSS's simple link element. 
  139. // 
  140. elseif ($this->feed_type == ATOM and $el == 'link' ) 
  141. if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' ) 
  142. $link_el = 'link'; 
  143. else { 
  144. $link_el = 'link_' . $attrs['rel']; 
  145.  
  146. $this->append($link_el, $attrs['href']); 
  147. // set stack[0] to current element 
  148. else { 
  149. array_unshift($this->stack, $el); 
  150.  
  151. function feed_cdata ($p, $text) { 
  152.  
  153. if ($this->feed_type == ATOM and $this->incontent) 
  154. $this->append_content( $text ); 
  155. else { 
  156. $current_el = join('_', array_reverse($this->stack)); 
  157. $this->append($current_el, $text); 
  158.  
  159. function feed_end_element ($p, $el) { 
  160. $el = strtolower($el); 
  161.  
  162. if ( $el == 'item' or $el == 'entry' ) 
  163. $this->items[] = $this->current_item; 
  164. $this->current_item = array(); 
  165. $this->initem = false; 
  166. elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' ) 
  167. $this->intextinput = false; 
  168. elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' ) 
  169. $this->inimage = false; 
  170. elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) 
  171. $this->incontent = false; 
  172. elseif ($el == 'channel' or $el == 'feed' ) 
  173. $this->inchannel = false; 
  174. elseif ($this->feed_type == ATOM and $this->incontent ) { 
  175. // balance tags properly 
  176. // note: This may not actually be necessary 
  177. if ( $this->stack[0] == $el ) 
  178. $this->append_content("</$el>"); 
  179. else { 
  180. $this->append_content("<$el />"); 
  181.  
  182. array_shift( $this->stack ); 
  183. else { 
  184. array_shift( $this->stack ); 
  185.  
  186. $this->current_namespace = false; 
  187.  
  188. function concat (&$str1, $str2="") { 
  189. if (!isset($str1) ) { 
  190. $str1=""; 
  191. $str1 .= $str2; 
  192.  
  193. function append_content($text) { 
  194. if ( $this->initem ) { 
  195. $this->concat( $this->current_item[ $this->incontent ], $text ); 
  196. elseif ( $this->inchannel ) { 
  197. $this->concat( $this->channel[ $this->incontent ], $text ); 
  198.  
  199. // smart append - field and namespace aware 
  200. function append($el, $text) { 
  201. if (!$el) { 
  202. return; 
  203. if ( $this->current_namespace ) 
  204. if ( $this->initem ) { 
  205. $this->concat( 
  206. $this->current_item[ $this->current_namespace ][ $el ], $text); 
  207. elseif ($this->inchannel) { 
  208. $this->concat( 
  209. $this->channel[ $this->current_namespace][ $el ], $text ); 
  210. elseif ($this->intextinput) { 
  211. $this->concat( 
  212. $this->textinput[ $this->current_namespace][ $el ], $text ); 
  213. elseif ($this->inimage) { 
  214. $this->concat( 
  215. $this->image[ $this->current_namespace ][ $el ], $text ); 
  216. else { 
  217. if ( $this->initem ) { 
  218. $this->concat( 
  219. $this->current_item[ $el ], $text); 
  220. elseif ($this->intextinput) { 
  221. $this->concat( 
  222. $this->textinput[ $el ], $text ); 
  223. elseif ($this->inimage) { 
  224. $this->concat( 
  225. $this->image[ $el ], $text ); 
  226. elseif ($this->inchannel) { 
  227. $this->concat( 
  228. $this->channel[ $el ], $text ); 
  229.  
  230.  
  231. function normalize () { 
  232. // if atom populate rss fields 
  233. if ( $this->is_atom() ) { 
  234. $this->channel['descripton'] = $this->channel['tagline']; 
  235. for ( $i = 0; $i < count($this->items); $i++) { 
  236. $item = $this->items[$i]; 
  237. if ( isset($item['summary']) ) 
  238. $item['description'] = $item['summary']; 
  239. if ( isset($item['atom_content'])) 
  240. $item['content']['encoded'] = $item['atom_content']; 
  241.  
  242. $this->items[$i] = $item; 
  243. elseif ( $this->is_rss() ) { 
  244. $this->channel['tagline'] = $this->channel['description']; 
  245. for ( $i = 0; $i < count($this->items); $i++) { 
  246. $item = $this->items[$i]; 
  247. if ( isset($item['description'])) 
  248. $item['summary'] = $item['description']; 
  249. if ( isset($item['content']['encoded'] ) ) 
  250. $item['atom_content'] = $item['content']['encoded']; 
  251.  
  252. $this->items[$i] = $item; 
  253.  
  254. function is_rss () { 
  255. if ( $this->feed_type == RSS ) { 
  256. return $this->feed_version; 
  257. else { 
  258. return false; 
  259.  
  260. function is_atom() { 
  261. if ( $this->feed_type == ATOM ) { 
  262. return $this->feed_version; 
  263. else { 
  264. return false; 
  265.  
  266. function map_attrs($k, $v) { 
  267. return "$k=\"$v\""; 
  268.  
  269. function error( $errormsg, $lvl = E_USER_WARNING ) { 
  270. // append PHP's error message if track_errors enabled 
  271. if ( isset($php_errormsg) ) { 
  272. $errormsg .= " ($php_errormsg)"; 
  273. if ( MAGPIE_DEBUG ) { 
  274. trigger_error( $errormsg, $lvl); 
  275. } else { 
  276. error_log( $errormsg, 0); 
  277.