PluginProbe
FeedWordPress / 2020.0118
FeedWordPress v2020.0118
trunk 0.8 0.9 0.91 0.95 0.96 0.97 0.98 0.981 0.99 0.991 0.992 0.993 2008.1030 2008.1101 2008.1105 2008.1214 2009.0612 2009.0613 2009.0618 2009.0707 2009.1111 2009.1112 2010.0127 2010.0528 All 65 releases
feedwordpress / feedwordpress_parser.class.php

feedwordpress_parser.class.php in FeedWordPress 2020.0118, at feedwordpress_parser.class.php

530 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 class FeedWordPress_Parser extends SimplePie_Parser {
3 function reset_parser (&$xml) {
4 // reset members
5 $this->namespace = array('');
6 $this->element = array('');
7 $this->xml_base = array('');
8 $this->xml_base_explicit = array(false);
9 $this->xml_lang = array('');
10 $this->data = array();
11 $this->datas = array(array());
12 $this->current_xhtml_construct = -1;
13 $this->xmlns_stack = array();
14 $this->xmlns_current = array();
15
16 // reset libxml parser
17 xml_parser_free($xml);
18
19 $xml = xml_parser_create_ns($this->encoding, $this->separator);
20 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
21 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
22 xml_set_object($xml, $this);
23 xml_set_character_data_handler($xml, 'cdata');
24 xml_set_element_handler($xml, 'tag_open', 'tag_close');
25 xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
26 }
27
28 public function parse (&$data, $encoding) {
29 $data = apply_filters('feedwordpress_parser_parse', $data, $encoding, $this);
30
31 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
32 if (strtoupper($encoding) === 'US-ASCII')
33 {
34 $this->encoding = 'UTF-8';
35 }
36 else
37 {
38 $this->encoding = $encoding;
39 }
40
41 // Strip BOM:
42 // UTF-32 Big Endian BOM
43 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
44 {
45 $data = substr($data, 4);
46 }
47 // UTF-32 Little Endian BOM
48 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
49 {
50 $data = substr($data, 4);
51 }
52 // UTF-16 Big Endian BOM
53 elseif (substr($data, 0, 2) === "\xFE\xFF")
54 {
55 $data = substr($data, 2);
56 }
57 // UTF-16 Little Endian BOM
58 elseif (substr($data, 0, 2) === "\xFF\xFE")
59 {
60 $data = substr($data, 2);
61 }
62 // UTF-8 BOM
63 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
64 {
65 $data = substr($data, 3);
66 }
67
68 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
69 {
70 $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
71 if ($declaration->parse())
72 {
73 $data = substr($data, $pos + 2);
74 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
75 }
76 else
77 {
78 $this->error_string = 'SimplePie bug! Please report this!';
79 return false;
80 }
81 }
82
83 $return = true;
84
85 static $xml_is_sane = null;
86 if ($xml_is_sane === null)
87 {
88 $parser_check = xml_parser_create();
89 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
90 xml_parser_free($parser_check);
91 $xml_is_sane = isset($values[0]['value']);
92 }
93
94 // Create the parser
95 if ($xml_is_sane)
96 {
97 $xml = xml_parser_create_ns($this->encoding, $this->separator);
98 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
99 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
100 xml_set_object($xml, $this);
101 xml_set_character_data_handler($xml, 'cdata');
102 xml_set_element_handler($xml, 'tag_open', 'tag_close');
103 xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
104
105 // Parse!
106 $parseResults = xml_parse($xml, $data, true);
107
108 $endOfJunk = strpos($data, '<?xml');
109 if (!$parseResults and $endOfJunk > 0) :
110 // There is some junk before the feed prolog. Try to get rid of it.
111 $data = substr($data, $endOfJunk);
112 $data = trim($data);
113 $this->reset_parser($xml);
114
115 $parseResults = xml_parse($xml, $data, true);
116 endif;
117
118 $badEntity = (xml_get_error_code($xml) == 26);
119 if (!$parseResults and $badEntity) :
120 // There was an entity that libxml couldn't understand.
121 // Chances are, it was a stray HTML entity. So let's try
122 // converting all the named HTML entities to numeric XML
123 // entities and starting over.
124 $data = $this->html_convert_entities($data);
125 $this->reset_parser($xml);
126
127 $parseResults = xml_parse($xml, $data, true);
128 endif;
129
130 if (!$parseResults) {
131 $this->error_code = xml_get_error_code($xml);
132 $this->error_string = xml_error_string($this->error_code);
133 $return = false;
134 }
135
136 $this->current_line = xml_get_current_line_number($xml);
137 $this->current_column = xml_get_current_column_number($xml);
138 $this->current_byte = xml_get_current_byte_index($xml);
139 xml_parser_free($xml);
140
141 return $return;
142 }
143 else
144 {
145 libxml_clear_errors();
146 $xml = new XMLReader();
147 $xml->xml($data);
148 while (@$xml->read())
149 {
150 switch ($xml->nodeType)
151 {
152
153 case constant('XMLReader::END_ELEMENT'):
154 if ($xml->namespaceURI !== '')
155 {
156 $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
157 }
158 else
159 {
160 $tagName = $xml->localName;
161 }
162 $this->tag_close(null, $tagName);
163 break;
164 case constant('XMLReader::ELEMENT'):
165 $empty = $xml->isEmptyElement;
166 if ($xml->namespaceURI !== '')
167 {
168 $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
169 }
170 else
171 {
172 $tagName = $xml->localName;
173 }
174 $attributes = array();
175 while ($xml->moveToNextAttribute())
176 {
177 if ($xml->namespaceURI !== '')
178 {
179 $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
180 }
181 else
182 {
183 $attrName = $xml->localName;
184 }
185 $attributes[$attrName] = $xml->value;
186 }
187
188 foreach ($attributes as $attr => $value) :
189 list($ns, $local) = $this->split_ns($attr);
190 if ($ns=='http://www.w3.org/2000/xmlns/') :
191 if ('xmlns' == $local) : $local = false; endif;
192 $this->start_xmlns(null, $local, $value);
193 endif;
194 endforeach;
195
196 $this->tag_open(null, $tagName, $attributes);
197 if ($empty)
198 {
199 $this->tag_close(null, $tagName);
200 }
201 break;
202 case constant('XMLReader::TEXT'):
203
204 case constant('XMLReader::CDATA'):
205 $this->cdata(null, $xml->value);
206 break;
207 }
208 }
209 if ($error = libxml_get_last_error())
210 {
211 $this->error_code = $error->code;
212 $this->error_string = $error->message;
213 $this->current_line = $error->line;
214 $this->current_column = $error->column;
215 return false;
216 }
217 else
218 {
219 return true;
220 }
221 }
222 } /* FeedWordPress_Parser::parse() */
223
224 var $xmlns_stack = array();
225 var $xmlns_current = array();
226 function tag_open ($parser, $tag, $attributes) {
227 $ret = parent::tag_open($parser, $tag, $attributes);
228 if ($this->current_xhtml_construct < 0) :
229 $this->data['xmlns'] = $this->xmlns_current;
230 $this->xmlns_stack[] = $this->xmlns_current;
231 endif;
232 return $ret;
233 }
234
235 function tag_close($parser, $tag) {
236 if ($this->current_xhtml_construct < 0) :
237 $this->xmlns_current = array_pop($this->xmlns_stack);
238 endif;
239 $ret = parent::tag_close($parser, $tag);
240 return $ret;
241 }
242
243 function start_xmlns ($parser, $prefix, $uri) {
244 if (!$prefix) :
245 $prefix = '';
246 endif;
247 if ($this->current_xhtml_construct < 0) :
248 $this->xmlns_current[$prefix] = $uri;
249 endif;
250 return true;
251 } /* FeedWordPress_Parser::start_xmlns() */
252
253 /* html_convert_entities($string) -- convert named HTML entities to
254 * XML-compatible numeric entities. Adapted from code by @inanimatt:
255 * https://gist.github.com/inanimatt/879249
256 */
257 public function html_convert_entities($string) {
258 return preg_replace_callback('/&([a-zA-Z][a-zA-Z0-9]+);/S',
259 array($this, 'convert_entity'), $string);
260 }
261
262 /* Swap HTML named entity with its numeric equivalent. If the entity
263 * isn't in the lookup table, this function returns a blank, which
264 * destroys the character in the output - this is probably the
265 * desired behaviour when producing XML. Adapted from code by @inanimatt:
266 * https://gist.github.com/inanimatt/879249
267 */
268 public function convert_entity($matches) {
269 static $table = array(
270 'quot' => '&#34;',
271 'amp' => '&#38;',
272 'lt' => '&#60;',
273 'gt' => '&#62;',
274 'OElig' => '&#338;',
275 'oelig' => '&#339;',
276 'Scaron' => '&#352;',
277 'scaron' => '&#353;',
278 'Yuml' => '&#376;',
279 'circ' => '&#710;',
280 'tilde' => '&#732;',
281 'ensp' => '&#8194;',
282 'emsp' => '&#8195;',
283 'thinsp' => '&#8201;',
284 'zwnj' => '&#8204;',
285 'zwj' => '&#8205;',
286 'lrm' => '&#8206;',
287 'rlm' => '&#8207;',
288 'ndash' => '&#8211;',
289 'mdash' => '&#8212;',
290 'lsquo' => '&#8216;',
291 'rsquo' => '&#8217;',
292 'sbquo' => '&#8218;',
293 'ldquo' => '&#8220;',
294 'rdquo' => '&#8221;',
295 'bdquo' => '&#8222;',
296 'dagger' => '&#8224;',
297 'Dagger' => '&#8225;',
298 'permil' => '&#8240;',
299 'lsaquo' => '&#8249;',
300 'rsaquo' => '&#8250;',
301 'euro' => '&#8364;',
302 'fnof' => '&#402;',
303 'Alpha' => '&#913;',
304 'Beta' => '&#914;',
305 'Gamma' => '&#915;',
306 'Delta' => '&#916;',
307 'Epsilon' => '&#917;',
308 'Zeta' => '&#918;',
309 'Eta' => '&#919;',
310 'Theta' => '&#920;',
311 'Iota' => '&#921;',
312 'Kappa' => '&#922;',
313 'Lambda' => '&#923;',
314 'Mu' => '&#924;',
315 'Nu' => '&#925;',
316 'Xi' => '&#926;',
317 'Omicron' => '&#927;',
318 'Pi' => '&#928;',
319 'Rho' => '&#929;',
320 'Sigma' => '&#931;',
321 'Tau' => '&#932;',
322 'Upsilon' => '&#933;',
323 'Phi' => '&#934;',
324 'Chi' => '&#935;',
325 'Psi' => '&#936;',
326 'Omega' => '&#937;',
327 'alpha' => '&#945;',
328 'beta' => '&#946;',
329 'gamma' => '&#947;',
330 'delta' => '&#948;',
331 'epsilon' => '&#949;',
332 'zeta' => '&#950;',
333 'eta' => '&#951;',
334 'theta' => '&#952;',
335 'iota' => '&#953;',
336 'kappa' => '&#954;',
337 'lambda' => '&#955;',
338 'mu' => '&#956;',
339 'nu' => '&#957;',
340 'xi' => '&#958;',
341 'omicron' => '&#959;',
342 'pi' => '&#960;',
343 'rho' => '&#961;',
344 'sigmaf' => '&#962;',
345 'sigma' => '&#963;',
346 'tau' => '&#964;',
347 'upsilon' => '&#965;',
348 'phi' => '&#966;',
349 'chi' => '&#967;',
350 'psi' => '&#968;',
351 'omega' => '&#969;',
352 'thetasym' => '&#977;',
353 'upsih' => '&#978;',
354 'piv' => '&#982;',
355 'bull' => '&#8226;',
356 'hellip' => '&#8230;',
357 'prime' => '&#8242;',
358 'Prime' => '&#8243;',
359 'oline' => '&#8254;',
360 'frasl' => '&#8260;',
361 'weierp' => '&#8472;',
362 'image' => '&#8465;',
363 'real' => '&#8476;',
364 'trade' => '&#8482;',
365 'alefsym' => '&#8501;',
366 'larr' => '&#8592;',
367 'uarr' => '&#8593;',
368 'rarr' => '&#8594;',
369 'darr' => '&#8595;',
370 'harr' => '&#8596;',
371 'crarr' => '&#8629;',
372 'lArr' => '&#8656;',
373 'uArr' => '&#8657;',
374 'rArr' => '&#8658;',
375 'dArr' => '&#8659;',
376 'hArr' => '&#8660;',
377 'forall' => '&#8704;',
378 'part' => '&#8706;',
379 'exist' => '&#8707;',
380 'empty' => '&#8709;',
381 'nabla' => '&#8711;',
382 'isin' => '&#8712;',
383 'notin' => '&#8713;',
384 'ni' => '&#8715;',
385 'prod' => '&#8719;',
386 'sum' => '&#8721;',
387 'minus' => '&#8722;',
388 'lowast' => '&#8727;',
389 'radic' => '&#8730;',
390 'prop' => '&#8733;',
391 'infin' => '&#8734;',
392 'ang' => '&#8736;',
393 'and' => '&#8743;',
394 'or' => '&#8744;',
395 'cap' => '&#8745;',
396 'cup' => '&#8746;',
397 'int' => '&#8747;',
398 'there4' => '&#8756;',
399 'sim' => '&#8764;',
400 'cong' => '&#8773;',
401 'asymp' => '&#8776;',
402 'ne' => '&#8800;',
403 'equiv' => '&#8801;',
404 'le' => '&#8804;',
405 'ge' => '&#8805;',
406 'sub' => '&#8834;',
407 'sup' => '&#8835;',
408 'nsub' => '&#8836;',
409 'sube' => '&#8838;',
410 'supe' => '&#8839;',
411 'oplus' => '&#8853;',
412 'otimes' => '&#8855;',
413 'perp' => '&#8869;',
414 'sdot' => '&#8901;',
415 'lceil' => '&#8968;',
416 'rceil' => '&#8969;',
417 'lfloor' => '&#8970;',
418 'rfloor' => '&#8971;',
419 'lang' => '&#9001;',
420 'rang' => '&#9002;',
421 'loz' => '&#9674;',
422 'spades' => '&#9824;',
423 'clubs' => '&#9827;',
424 'hearts' => '&#9829;',
425 'diams' => '&#9830;',
426 'nbsp' => '&#160;',
427 'iexcl' => '&#161;',
428 'cent' => '&#162;',
429 'pound' => '&#163;',
430 'curren' => '&#164;',
431 'yen' => '&#165;',
432 'brvbar' => '&#166;',
433 'sect' => '&#167;',
434 'uml' => '&#168;',
435 'copy' => '&#169;',
436 'ordf' => '&#170;',
437 'laquo' => '&#171;',
438 'not' => '&#172;',
439 'shy' => '&#173;',
440 'reg' => '&#174;',
441 'macr' => '&#175;',
442 'deg' => '&#176;',
443 'plusmn' => '&#177;',
444 'sup2' => '&#178;',
445 'sup3' => '&#179;',
446 'acute' => '&#180;',
447 'micro' => '&#181;',
448 'para' => '&#182;',
449 'middot' => '&#183;',
450 'cedil' => '&#184;',
451 'sup1' => '&#185;',
452 'ordm' => '&#186;',
453 'raquo' => '&#187;',
454 'frac14' => '&#188;',
455 'frac12' => '&#189;',
456 'frac34' => '&#190;',
457 'iquest' => '&#191;',
458 'Agrave' => '&#192;',
459 'Aacute' => '&#193;',
460 'Acirc' => '&#194;',
461 'Atilde' => '&#195;',
462 'Auml' => '&#196;',
463 'Aring' => '&#197;',
464 'AElig' => '&#198;',
465 'Ccedil' => '&#199;',
466 'Egrave' => '&#200;',
467 'Eacute' => '&#201;',
468 'Ecirc' => '&#202;',
469 'Euml' => '&#203;',
470 'Igrave' => '&#204;',
471 'Iacute' => '&#205;',
472 'Icirc' => '&#206;',
473 'Iuml' => '&#207;',
474 'ETH' => '&#208;',
475 'Ntilde' => '&#209;',
476 'Ograve' => '&#210;',
477 'Oacute' => '&#211;',
478 'Ocirc' => '&#212;',
479 'Otilde' => '&#213;',
480 'Ouml' => '&#214;',
481 'times' => '&#215;',
482 'Oslash' => '&#216;',
483 'Ugrave' => '&#217;',
484 'Uacute' => '&#218;',
485 'Ucirc' => '&#219;',
486 'Uuml' => '&#220;',
487 'Yacute' => '&#221;',
488 'THORN' => '&#222;',
489 'szlig' => '&#223;',
490 'agrave' => '&#224;',
491 'aacute' => '&#225;',
492 'acirc' => '&#226;',
493 'atilde' => '&#227;',
494 'auml' => '&#228;',
495 'aring' => '&#229;',
496 'aelig' => '&#230;',
497 'ccedil' => '&#231;',
498 'egrave' => '&#232;',
499 'eacute' => '&#233;',
500 'ecirc' => '&#234;',
501 'euml' => '&#235;',
502 'igrave' => '&#236;',
503 'iacute' => '&#237;',
504 'icirc' => '&#238;',
505 'iuml' => '&#239;',
506 'eth' => '&#240;',
507 'ntilde' => '&#241;',
508 'ograve' => '&#242;',
509 'oacute' => '&#243;',
510 'ocirc' => '&#244;',
511 'otilde' => '&#245;',
512 'ouml' => '&#246;',
513 'divide' => '&#247;',
514 'oslash' => '&#248;',
515 'ugrave' => '&#249;',
516 'uacute' => '&#250;',
517 'ucirc' => '&#251;',
518 'uuml' => '&#252;',
519 'yacute' => '&#253;',
520 'thorn' => '&#254;',
521 'yuml' => '&#255;'
522 );
523 // Entity not found? Destroy it.
524 return isset($table[$matches[1]]) ? $table[$matches[1]] : '';
525 } /* FeedWordPress_Parser::convert_entity() */
526
527 } /* class FeedWordPress_Parser */
528
529
530