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