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

/simplepie.class.php

https://github.com/gsnedders/simplepie
PHP | 5687 lines | 5084 code | 212 blank | 391 comment | 294 complexity | 50aa67317f406060f180b02cb719e29a MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * SimplePie
  4. *
  5. * A PHP-Based RSS and Atom Feed Framework.
  6. * Takes the hard work out of managing a complete RSS/Atom solution.
  7. *
  8. * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without modification, are
  12. * permitted provided that the following conditions are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright notice, this list of
  15. * conditions and the following disclaimer.
  16. *
  17. * * Redistributions in binary form must reproduce the above copyright notice, this list
  18. * of conditions and the following disclaimer in the documentation and/or other materials
  19. * provided with the distribution.
  20. *
  21. * * Neither the name of the SimplePie Team nor the names of its contributors may be used
  22. * to endorse or promote products derived from this software without specific prior
  23. * written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  26. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  27. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  28. * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  30. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  32. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. * @package SimplePie
  36. * @version 2.0-dev
  37. * @copyright 2004-2009 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  38. * @author Ryan Parman
  39. * @author Geoffrey Sneddon
  40. * @author Ryan McCue
  41. * @link http://simplepie.org/ SimplePie
  42. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  43. * @todo phpDoc comments
  44. */
  45. /**
  46. * SimplePie Name
  47. */
  48. define('SIMPLEPIE_NAME', 'SimplePie');
  49. /**
  50. * SimplePie Version
  51. */
  52. define('SIMPLEPIE_VERSION', '2.0-dev');
  53. /**
  54. * SimplePie Build
  55. * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::parse_date() only every load of simplepie.inc)
  56. */
  57. define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::parse_date(substr('$Date$', 7, 25)) ? SimplePie_Misc::parse_date(substr('$Date$', 7, 25)) : filemtime(__FILE__)));
  58. /**
  59. * SimplePie Website URL
  60. */
  61. define('SIMPLEPIE_URL', 'http://simplepie.org');
  62. /**
  63. * SimplePie Useragent
  64. * This can be passed into whatever HTTP class you use.
  65. */
  66. define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . ') Build/' . SIMPLEPIE_BUILD);
  67. /**
  68. * No known feed type
  69. */
  70. define('SIMPLEPIE_TYPE_NONE', 0);
  71. /**
  72. * RSS 0.90
  73. */
  74. define('SIMPLEPIE_TYPE_RSS_090', 1);
  75. /**
  76. * RSS 0.91 (Netscape)
  77. */
  78. define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
  79. /**
  80. * RSS 0.91 (Userland)
  81. */
  82. define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
  83. /**
  84. * RSS 0.91 (both Netscape and Userland)
  85. */
  86. define('SIMPLEPIE_TYPE_RSS_091', 6);
  87. /**
  88. * RSS 0.92
  89. */
  90. define('SIMPLEPIE_TYPE_RSS_092', 8);
  91. /**
  92. * RSS 0.93
  93. */
  94. define('SIMPLEPIE_TYPE_RSS_093', 16);
  95. /**
  96. * RSS 0.94
  97. */
  98. define('SIMPLEPIE_TYPE_RSS_094', 32);
  99. /**
  100. * RSS 1.0
  101. */
  102. define('SIMPLEPIE_TYPE_RSS_10', 64);
  103. /**
  104. * RSS 2.0
  105. */
  106. define('SIMPLEPIE_TYPE_RSS_20', 128);
  107. /**
  108. * RDF-based RSS
  109. */
  110. define('SIMPLEPIE_TYPE_RSS_RDF', 65);
  111. /**
  112. * Non-RDF-based RSS (truly intended as syndication format)
  113. */
  114. define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
  115. /**
  116. * All RSS
  117. */
  118. define('SIMPLEPIE_TYPE_RSS_ALL', 255);
  119. /**
  120. * Atom 0.3
  121. */
  122. define('SIMPLEPIE_TYPE_ATOM_03', 256);
  123. /**
  124. * Atom 1.0
  125. */
  126. define('SIMPLEPIE_TYPE_ATOM_10', 512);
  127. /**
  128. * All Atom
  129. */
  130. define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
  131. /**
  132. * All feed types
  133. */
  134. define('SIMPLEPIE_TYPE_ALL', 1023);
  135. /**
  136. * No construct
  137. */
  138. define('SIMPLEPIE_CONSTRUCT_NONE', 0);
  139. /**
  140. * Text construct
  141. */
  142. define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
  143. /**
  144. * HTML construct
  145. */
  146. define('SIMPLEPIE_CONSTRUCT_HTML', 2);
  147. /**
  148. * XHTML construct
  149. */
  150. define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
  151. /**
  152. * base64-encoded construct
  153. */
  154. define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
  155. /**
  156. * IRI construct
  157. */
  158. define('SIMPLEPIE_CONSTRUCT_IRI', 16);
  159. /**
  160. * All constructs
  161. */
  162. define('SIMPLEPIE_CONSTRUCT_ALL', 63);
  163. /**
  164. * Don't change case
  165. */
  166. define('SIMPLEPIE_SAME_CASE', 1);
  167. /**
  168. * Change to lowercase
  169. */
  170. define('SIMPLEPIE_LOWERCASE', 2);
  171. /**
  172. * Change to uppercase
  173. */
  174. define('SIMPLEPIE_UPPERCASE', 4);
  175. /**
  176. * PCRE for HTML attributes
  177. */
  178. define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
  179. /**
  180. * PCRE for XML attributes
  181. */
  182. define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
  183. /**
  184. * XML Namespace
  185. */
  186. define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
  187. /**
  188. * Atom 1.0 Namespace
  189. */
  190. define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
  191. /**
  192. * Atom 0.3 Namespace
  193. */
  194. define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
  195. /**
  196. * RDF Namespace
  197. */
  198. define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
  199. /**
  200. * RSS 0.90 Namespace
  201. */
  202. define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
  203. /**
  204. * RSS 1.0 Namespace
  205. */
  206. define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
  207. /**
  208. * RSS 1.0 Content Module Namespace
  209. */
  210. define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
  211. /**
  212. * RSS 2.0 Namespace
  213. * (Stupid, I know, but I'm certain it will confuse people less with support.)
  214. */
  215. define('SIMPLEPIE_NAMESPACE_RSS_20', '');
  216. /**
  217. * DC 1.0 Namespace
  218. */
  219. define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
  220. /**
  221. * DC 1.1 Namespace
  222. */
  223. define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
  224. /**
  225. * XHTML Namespace
  226. */
  227. define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
  228. /**
  229. * IANA Link Relations Registry
  230. */
  231. define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
  232. /**
  233. * SimplePie
  234. *
  235. * @package SimplePie
  236. */
  237. class SimplePie
  238. {
  239. /**
  240. * @var array Raw data
  241. * @access private
  242. */
  243. public $data = array();
  244. /**
  245. * @var mixed Error string
  246. * @access private
  247. */
  248. public $error;
  249. /**
  250. * @var object Instance of SimplePie_Sanitize (or other class)
  251. * @see SimplePie::set_sanitize_class()
  252. * @access private
  253. */
  254. public $sanitize;
  255. /**
  256. * @var string Raw feed data
  257. * @see SimplePie::set_raw_data()
  258. * @access private
  259. */
  260. public $raw_data;
  261. /**
  262. * @var string Class used for parsing feeds
  263. * @see SimplePie::set_parser_class()
  264. * @access private
  265. */
  266. public $parser_class = 'SimplePie_Parser';
  267. /**
  268. * @var string Class used for items
  269. * @see SimplePie::set_item_class()
  270. * @access private
  271. */
  272. public $item_class = 'SimplePie_Item';
  273. /**
  274. * @var string Class used for authors
  275. * @see SimplePie::set_author_class()
  276. * @access private
  277. */
  278. public $author_class = 'SimplePie_Author';
  279. /**
  280. * @var string Class used for categories
  281. * @see SimplePie::set_category_class()
  282. * @access private
  283. */
  284. public $category_class = 'SimplePie_Category';
  285. /**
  286. * @var string Class used for enclosures
  287. * @see SimplePie::set_enclosures_class()
  288. * @access private
  289. */
  290. public $enclosure_class = 'SimplePie_Enclosure';
  291. /**
  292. * @var string Class used for item sources.
  293. * @see SimplePie::set_source_class()
  294. * @access private
  295. */
  296. public $source_class = 'SimplePie_Source';
  297. /**
  298. * The SimplePie class contains feed level data and options
  299. *
  300. * There are two ways that you can create a new SimplePie object. The first
  301. * is by passing a feed URL as a parameter to the SimplePie constructor
  302. * (as well as optionally setting the cache location and cache expiry). This
  303. * will initialise the whole feed with all of the default settings, and you
  304. * can begin accessing methods and properties immediately.
  305. *
  306. * The second way is to create the SimplePie object with no parameters
  307. * at all. This will enable you to set configuration options. After setting
  308. * them, you must initialise the feed using $feed->init(). At that point the
  309. * object's methods and properties will be available to you. This format is
  310. * what is used throughout this documentation.
  311. *
  312. * @access public
  313. * @since 1.0 Preview Release
  314. */
  315. public function __construct()
  316. {
  317. // Other objects, instances created here so we can set options on them
  318. $this->sanitize = new SimplePie_Sanitize();
  319. }
  320. /**
  321. * Used for converting object to a string
  322. */
  323. public function __toString()
  324. {
  325. return md5(serialize($this->data));
  326. }
  327. /**
  328. * Remove items that link back to this before destroying this object
  329. */
  330. public function __destruct()
  331. {
  332. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  333. {
  334. if (!empty($this->data['items']))
  335. {
  336. foreach ($this->data['items'] as $item)
  337. {
  338. $item->__destruct();
  339. }
  340. unset($item, $this->data['items']);
  341. }
  342. if (!empty($this->data['ordered_items']))
  343. {
  344. foreach ($this->data['ordered_items'] as $item)
  345. {
  346. $item->__destruct();
  347. }
  348. unset($item, $this->data['ordered_items']);
  349. }
  350. }
  351. }
  352. /**
  353. * Allows you to use a string of RSS/Atom data instead of a remote feed.
  354. *
  355. * If you have a feed available as a string in PHP, you can tell SimplePie
  356. * to parse that data string instead of a remote feed. Any set feed URL
  357. * takes precedence.
  358. *
  359. * @access public
  360. * @since 1.0 Beta 3
  361. * @param string $data RSS or Atom data as a string.
  362. */
  363. public function set_raw_data($data)
  364. {
  365. $this->raw_data = $data;
  366. }
  367. /**
  368. * Allows you to change which class SimplePie uses for XML parsing.
  369. * Useful when you are overloading or extending SimplePie's default classes.
  370. *
  371. * @access public
  372. * @param string $class Name of custom class.
  373. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  374. */
  375. public function set_parser_class($class = 'SimplePie_Parser')
  376. {
  377. if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser'))
  378. {
  379. $this->parser_class = $class;
  380. return true;
  381. }
  382. return false;
  383. }
  384. /**
  385. * Allows you to change which class SimplePie uses for data sanitization.
  386. * Useful when you are overloading or extending SimplePie's default classes.
  387. *
  388. * @access public
  389. * @param string $class Name of custom class.
  390. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  391. */
  392. public function set_sanitize_class($class = 'SimplePie_Sanitize')
  393. {
  394. if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize'))
  395. {
  396. $this->sanitize = new $class();
  397. return true;
  398. }
  399. return false;
  400. }
  401. /**
  402. * Allows you to change which class SimplePie uses for handling feed items.
  403. * Useful when you are overloading or extending SimplePie's default classes.
  404. *
  405. * @access public
  406. * @param string $class Name of custom class.
  407. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  408. */
  409. public function set_item_class($class = 'SimplePie_Item')
  410. {
  411. if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item'))
  412. {
  413. $this->item_class = $class;
  414. return true;
  415. }
  416. return false;
  417. }
  418. /**
  419. * Allows you to change which class SimplePie uses for handling author data.
  420. * Useful when you are overloading or extending SimplePie's default classes.
  421. *
  422. * @access public
  423. * @param string $class Name of custom class.
  424. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  425. */
  426. public function set_author_class($class = 'SimplePie_Author')
  427. {
  428. if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author'))
  429. {
  430. $this->author_class = $class;
  431. return true;
  432. }
  433. return false;
  434. }
  435. /**
  436. * Allows you to change which class SimplePie uses for handling category data.
  437. * Useful when you are overloading or extending SimplePie's default classes.
  438. *
  439. * @access public
  440. * @param string $class Name of custom class.
  441. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  442. */
  443. public function set_category_class($class = 'SimplePie_Category')
  444. {
  445. if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category'))
  446. {
  447. $this->category_class = $class;
  448. return true;
  449. }
  450. return false;
  451. }
  452. /**
  453. * Allows you to change which class SimplePie uses for feed enclosures.
  454. * Useful when you are overloading or extending SimplePie's default classes.
  455. *
  456. * @access public
  457. * @param string $class Name of custom class.
  458. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  459. */
  460. public function set_enclosure_class($class = 'SimplePie_Enclosure')
  461. {
  462. if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure'))
  463. {
  464. $this->enclosure_class = $class;
  465. return true;
  466. }
  467. return false;
  468. }
  469. /**
  470. * Allows you to change which class SimplePie uses item sources.
  471. * Useful when you are overloading or extending SimplePie's default classes.
  472. *
  473. * @access public
  474. * @param string $class Name of custom class.
  475. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  476. */
  477. public function set_source_class($class = 'SimplePie_Source')
  478. {
  479. if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source'))
  480. {
  481. $this->source_class = $class;
  482. return true;
  483. }
  484. return false;
  485. }
  486. /**
  487. * Set element/attribute key/value pairs of HTML attributes
  488. * containing URLs that need to be resolved relative to the feed
  489. *
  490. * @access public
  491. * @since 1.0
  492. * @param array $element_attribute Element/attribute key/value pairs
  493. */
  494. public function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
  495. {
  496. $this->sanitize->set_url_replacements($element_attribute);
  497. }
  498. public function init()
  499. {
  500. // Check the xml extension is sane (i.e., libxml 2.7.x issue on PHP < 5.2.9 and libxml 2.7.0 to 2.7.2 on any version) if we don't have xmlreader.
  501. if (!extension_loaded('xmlreader'))
  502. {
  503. static $xml_is_sane = null;
  504. if ($xml_is_sane === null)
  505. {
  506. $parser_check = xml_parser_create();
  507. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  508. xml_parser_free($parser_check);
  509. $xml_is_sane = isset($values[0]['value']);
  510. }
  511. if (!$xml_is_sane)
  512. {
  513. return false;
  514. }
  515. }
  516. if ($this->raw_data !== null)
  517. {
  518. $this->error = null;
  519. $this->data = array();
  520. $data = $this->raw_data;
  521. // Create new parser
  522. $parser = new $this->parser_class();
  523. // If it's parsed fine
  524. if ($parser->parse($data, 'UTF-8'))
  525. {
  526. $this->data = $parser->get_data();
  527. if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE)
  528. {
  529. $this->data['build'] = SIMPLEPIE_BUILD;
  530. return true;
  531. }
  532. else
  533. {
  534. $this->error = "This does not appear to be a valid RSS or Atom feed.";
  535. SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
  536. return false;
  537. }
  538. }
  539. else
  540. {
  541. // We have an error, just set SimplePie_Misc::error to it and quit
  542. $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
  543. }
  544. SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
  545. return false;
  546. }
  547. else
  548. {
  549. return false;
  550. }
  551. }
  552. /**
  553. * Return the error message for the occured error
  554. *
  555. * @access public
  556. * @return string Error message
  557. */
  558. public function error()
  559. {
  560. return $this->error;
  561. }
  562. public function get_type()
  563. {
  564. if (!isset($this->data['type']))
  565. {
  566. $this->data['type'] = SIMPLEPIE_TYPE_ALL;
  567. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
  568. {
  569. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
  570. }
  571. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
  572. {
  573. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
  574. }
  575. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
  576. {
  577. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
  578. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
  579. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
  580. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
  581. {
  582. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
  583. }
  584. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
  585. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
  586. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
  587. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
  588. {
  589. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
  590. }
  591. }
  592. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
  593. {
  594. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
  595. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  596. {
  597. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  598. {
  599. case '0.91':
  600. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
  601. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  602. {
  603. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  604. {
  605. case '0':
  606. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
  607. break;
  608. case '24':
  609. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
  610. break;
  611. }
  612. }
  613. break;
  614. case '0.92':
  615. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
  616. break;
  617. case '0.93':
  618. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
  619. break;
  620. case '0.94':
  621. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
  622. break;
  623. case '2.0':
  624. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
  625. break;
  626. }
  627. }
  628. }
  629. else
  630. {
  631. $this->data['type'] = SIMPLEPIE_TYPE_NONE;
  632. }
  633. }
  634. return $this->data['type'];
  635. }
  636. public function get_feed_tags($namespace, $tag)
  637. {
  638. $type = $this->get_type();
  639. if ($type & SIMPLEPIE_TYPE_ATOM_10)
  640. {
  641. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
  642. {
  643. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
  644. }
  645. }
  646. if ($type & SIMPLEPIE_TYPE_ATOM_03)
  647. {
  648. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
  649. {
  650. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
  651. }
  652. }
  653. if ($type & SIMPLEPIE_TYPE_RSS_RDF)
  654. {
  655. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
  656. {
  657. return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
  658. }
  659. }
  660. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  661. {
  662. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
  663. {
  664. return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
  665. }
  666. }
  667. return null;
  668. }
  669. public function get_channel_tags($namespace, $tag)
  670. {
  671. $type = $this->get_type();
  672. if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
  673. {
  674. if ($return = $this->get_feed_tags($namespace, $tag))
  675. {
  676. return $return;
  677. }
  678. }
  679. if ($type & SIMPLEPIE_TYPE_RSS_10)
  680. {
  681. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
  682. {
  683. if (isset($channel[0]['child'][$namespace][$tag]))
  684. {
  685. return $channel[0]['child'][$namespace][$tag];
  686. }
  687. }
  688. }
  689. if ($type & SIMPLEPIE_TYPE_RSS_090)
  690. {
  691. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
  692. {
  693. if (isset($channel[0]['child'][$namespace][$tag]))
  694. {
  695. return $channel[0]['child'][$namespace][$tag];
  696. }
  697. }
  698. }
  699. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  700. {
  701. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
  702. {
  703. if (isset($channel[0]['child'][$namespace][$tag]))
  704. {
  705. return $channel[0]['child'][$namespace][$tag];
  706. }
  707. }
  708. }
  709. return null;
  710. }
  711. public function get_image_tags($namespace, $tag)
  712. {
  713. $type = $this->get_type();
  714. if ($type & SIMPLEPIE_TYPE_RSS_10)
  715. {
  716. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
  717. {
  718. if (isset($image[0]['child'][$namespace][$tag]))
  719. {
  720. return $image[0]['child'][$namespace][$tag];
  721. }
  722. }
  723. }
  724. if ($type & SIMPLEPIE_TYPE_RSS_090)
  725. {
  726. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
  727. {
  728. if (isset($image[0]['child'][$namespace][$tag]))
  729. {
  730. return $image[0]['child'][$namespace][$tag];
  731. }
  732. }
  733. }
  734. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  735. {
  736. if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
  737. {
  738. if (isset($image[0]['child'][$namespace][$tag]))
  739. {
  740. return $image[0]['child'][$namespace][$tag];
  741. }
  742. }
  743. }
  744. return null;
  745. }
  746. public function get_base($element = array())
  747. {
  748. if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
  749. {
  750. return $element['xml_base'];
  751. }
  752. elseif ($this->get_link() !== null)
  753. {
  754. return $this->get_link();
  755. }
  756. else
  757. {
  758. return '';
  759. }
  760. }
  761. public function sanitize($data, $type, $base = '')
  762. {
  763. return $this->sanitize->sanitize($data, $type, $base);
  764. }
  765. public function get_title()
  766. {
  767. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  768. {
  769. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  770. }
  771. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  772. {
  773. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  774. }
  775. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  776. {
  777. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  778. }
  779. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  780. {
  781. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  782. }
  783. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  784. {
  785. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  786. }
  787. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  788. {
  789. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  790. }
  791. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  792. {
  793. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  794. }
  795. else
  796. {
  797. return null;
  798. }
  799. }
  800. public function get_category($key = 0)
  801. {
  802. $categories = $this->get_categories();
  803. if (isset($categories[$key]))
  804. {
  805. return $categories[$key];
  806. }
  807. else
  808. {
  809. return null;
  810. }
  811. }
  812. public function get_categories()
  813. {
  814. $categories = array();
  815. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  816. {
  817. $term = null;
  818. $scheme = null;
  819. $label = null;
  820. if (isset($category['attribs']['']['term']))
  821. {
  822. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  823. }
  824. if (isset($category['attribs']['']['scheme']))
  825. {
  826. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  827. }
  828. if (isset($category['attribs']['']['label']))
  829. {
  830. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  831. }
  832. $categories[] = new $this->category_class($term, $scheme, $label);
  833. }
  834. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  835. {
  836. // This is really the label, but keep this as the term also for BC.
  837. // Label will also work on retrieving because that falls back to term.
  838. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  839. if (isset($category['attribs']['']['domain']))
  840. {
  841. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  842. }
  843. else
  844. {
  845. $scheme = null;
  846. }
  847. $categories[] = new $this->category_class($term, $scheme, null);
  848. }
  849. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  850. {
  851. $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  852. }
  853. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  854. {
  855. $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  856. }
  857. if (!empty($categories))
  858. {
  859. return SimplePie_Misc::array_unique($categories);
  860. }
  861. else
  862. {
  863. return null;
  864. }
  865. }
  866. public function get_author($key = 0)
  867. {
  868. $authors = $this->get_authors();
  869. if (isset($authors[$key]))
  870. {
  871. return $authors[$key];
  872. }
  873. else
  874. {
  875. return null;
  876. }
  877. }
  878. public function get_authors()
  879. {
  880. $authors = array();
  881. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  882. {
  883. $name = null;
  884. $uri = null;
  885. $email = null;
  886. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  887. {
  888. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  889. }
  890. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  891. {
  892. $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
  893. }
  894. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  895. {
  896. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  897. }
  898. if ($name !== null || $email !== null || $uri !== null)
  899. {
  900. $authors[] = new $this->author_class($name, $uri, $email);
  901. }
  902. }
  903. if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  904. {
  905. $name = null;
  906. $url = null;
  907. $email = null;
  908. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  909. {
  910. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  911. }
  912. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  913. {
  914. $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
  915. }
  916. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  917. {
  918. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  919. }
  920. if ($name !== null || $email !== null || $url !== null)
  921. {
  922. $authors[] = new $this->author_class($name, $url, $email);
  923. }
  924. }
  925. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  926. {
  927. $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  928. }
  929. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  930. {
  931. $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  932. }
  933. if (!empty($authors))
  934. {
  935. return SimplePie_Misc::array_unique($authors);
  936. }
  937. else
  938. {
  939. return null;
  940. }
  941. }
  942. public function get_contributor($key = 0)
  943. {
  944. $contributors = $this->get_contributors();
  945. if (isset($contributors[$key]))
  946. {
  947. return $contributors[$key];
  948. }
  949. else
  950. {
  951. return null;
  952. }
  953. }
  954. public function get_contributors()
  955. {
  956. $contributors = array();
  957. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  958. {
  959. $name = null;
  960. $uri = null;
  961. $email = null;
  962. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  963. {
  964. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  965. }
  966. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  967. {
  968. $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
  969. }
  970. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  971. {
  972. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  973. }
  974. if ($name !== null || $email !== null || $uri !== null)
  975. {
  976. $contributors[] = new $this->author_class($name, $uri, $email);
  977. }
  978. }
  979. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  980. {
  981. $name = null;
  982. $url = null;
  983. $email = null;
  984. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  985. {
  986. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  987. }
  988. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  989. {
  990. $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
  991. }
  992. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  993. {
  994. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  995. }
  996. if ($name !== null || $email !== null || $url !== null)
  997. {
  998. $contributors[] = new $this->author_class($name, $url, $email);
  999. }
  1000. }
  1001. if (!empty($contributors))
  1002. {
  1003. return SimplePie_Misc::array_unique($contributors);
  1004. }
  1005. else
  1006. {
  1007. return null;
  1008. }
  1009. }
  1010. public function get_link($key = 0, $rel = 'alternate')
  1011. {
  1012. $links = $this->get_links($rel);
  1013. if (isset($links[$key]))
  1014. {
  1015. return $links[$key];
  1016. }
  1017. else
  1018. {
  1019. return null;
  1020. }
  1021. }
  1022. /**
  1023. * Added for parity between the parent-level and the item/entry-level.
  1024. */
  1025. public function get_permalink()
  1026. {
  1027. return $this->get_link(0);
  1028. }
  1029. public function get_links($rel = 'alternate')
  1030. {
  1031. if (!isset($this->data['links']))
  1032. {
  1033. $this->data['links'] = array();
  1034. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  1035. {
  1036. foreach ($links as $link)
  1037. {
  1038. if (isset($link['attribs']['']['href']))
  1039. {
  1040. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  1041. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  1042. }
  1043. }
  1044. }
  1045. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  1046. {
  1047. foreach ($links as $link)
  1048. {
  1049. if (isset($link['attribs']['']['href']))
  1050. {
  1051. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  1052. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  1053. }
  1054. }
  1055. }
  1056. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  1057. {
  1058. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  1059. }
  1060. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  1061. {
  1062. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  1063. }
  1064. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  1065. {
  1066. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  1067. }
  1068. $keys = array_keys($this->data['links']);
  1069. foreach ($keys as $key)
  1070. {
  1071. if (SimplePie_Misc::is_isegment_nz_nc($key))
  1072. {
  1073. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  1074. {
  1075. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  1076. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  1077. }
  1078. else
  1079. {
  1080. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  1081. }
  1082. }
  1083. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  1084. {
  1085. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  1086. }
  1087. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  1088. }
  1089. }
  1090. if (isset($this->data['links'][$rel]))
  1091. {
  1092. return $this->data['links'][$rel];
  1093. }
  1094. else
  1095. {
  1096. return null;
  1097. }
  1098. }
  1099. public function get_description()
  1100. {
  1101. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  1102. {
  1103. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1104. }
  1105. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  1106. {
  1107. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1108. }
  1109. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  1110. {
  1111. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1112. }
  1113. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  1114. {
  1115. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1116. }
  1117. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  1118. {
  1119. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1120. }
  1121. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  1122. {
  1123. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1124. }
  1125. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  1126. {
  1127. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1128. }
  1129. else
  1130. {
  1131. return null;
  1132. }
  1133. }
  1134. public function get_copyright()
  1135. {
  1136. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  1137. {
  1138. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1139. }
  1140. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  1141. {
  1142. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1143. }
  1144. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  1145. {
  1146. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1147. }
  1148. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  1149. {
  1150. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1151. }
  1152. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  1153. {
  1154. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1155. }
  1156. else
  1157. {
  1158. return null;
  1159. }
  1160. }
  1161. public function get_language()
  1162. {
  1163. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  1164. {
  1165. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1166. }
  1167. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  1168. {
  1169. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1170. }
  1171. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  1172. {
  1173. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1174. }
  1175. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
  1176. {
  1177. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  1178. }
  1179. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
  1180. {
  1181. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  1182. }
  1183. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
  1184. {
  1185. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  1186. }
  1187. elseif (isset($this->data['headers']['content-language']))
  1188. {
  1189. return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
  1190. }
  1191. else
  1192. {
  1193. return null;
  1194. }
  1195. }
  1196. public function get_image_title()
  1197. {
  1198. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  1199. {
  1200. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1201. }
  1202. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  1203. {
  1204. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1205. }
  1206. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  1207. {
  1208. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1209. }
  1210. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  1211. {
  1212. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1213. }
  1214. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  1215. {
  1216. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1217. }
  1218. else
  1219. {
  1220. return null;
  1221. }
  1222. }
  1223. public function get_image_url()
  1224. {
  1225. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  1226. {
  1227. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1228. }
  1229. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  1230. {
  1231. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1232. }
  1233. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
  1234. {
  1235. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1236. }
  1237. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
  1238. {
  1239. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1240. }
  1241. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  1242. {
  1243. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1244. }
  1245. else
  1246. {
  1247. return null;
  1248. }
  1249. }
  1250. public function get_image_link()
  1251. {
  1252. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  1253. {
  1254. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1255. }
  1256. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  1257. {
  1258. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1259. }
  1260. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  1261. {
  1262. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  1263. }
  1264. else
  1265. {
  1266. return null;
  1267. }
  1268. }
  1269. public function get_image_width()
  1270. {
  1271. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
  1272. {
  1273. return round($return[0]['data']);
  1274. }
  1275. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  1276. {
  1277. return 88.0;
  1278. }
  1279. else
  1280. {
  1281. return null;
  1282. }
  1283. }
  1284. public function get_image_height()
  1285. {
  1286. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
  1287. {
  1288. return round($return[0]['data']);
  1289. }
  1290. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  1291. {
  1292. return 31.0;
  1293. }
  1294. else
  1295. {
  1296. return null;
  1297. }
  1298. }
  1299. public function get_item_quantity($max = 0)
  1300. {
  1301. $max = (int) $max;
  1302. $qty = count($this->get_items());
  1303. if ($max === 0)
  1304. {
  1305. return $qty;
  1306. }
  1307. else
  1308. {
  1309. return ($qty > $max) ? $max : $qty;
  1310. }
  1311. }
  1312. public function get_item($key = 0)
  1313. {
  1314. $items = $this->get_items();
  1315. if (isset($items[$key]))
  1316. {
  1317. return $items[$key];
  1318. }
  1319. else
  1320. {
  1321. return null;
  1322. }
  1323. }
  1324. public function get_items()
  1325. {
  1326. if (!isset($this->data['items']))
  1327. {
  1328. $this->data['items'] = array();
  1329. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
  1330. {
  1331. $keys = array_keys($items);
  1332. foreach ($keys as $key)
  1333. {
  1334. $this->data['items'][] = new $this->item_class($this, $items[$key]);
  1335. }
  1336. }
  1337. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
  1338. {
  1339. $keys = array_keys($items);
  1340. foreach ($keys as $key)
  1341. {
  1342. $this->data['items'][] = new $this->item_class($this, $items[$key]);
  1343. }
  1344. }
  1345. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
  1346. {
  1347. $keys = array_keys($items);
  1348. foreach ($keys as $key)
  1349. {
  1350. $this->data['items'][] = new $this->item_class($this, $items[$key]);
  1351. }
  1352. }
  1353. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
  1354. {
  1355. $keys = array_keys($items);
  1356. foreach ($keys as $key)
  1357. {
  1358. $this->data['items'][] = new $this->item_class($this, $items[$key]);
  1359. }
  1360. }
  1361. if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
  1362. {
  1363. $keys = array_keys($items);
  1364. foreach ($keys as $key)
  1365. {
  1366. $this->data['items'][] = new $this->item_class($this, $items[$key]);
  1367. }
  1368. }
  1369. }
  1370. if (!empty($this->data['items']))
  1371. {
  1372. return $this->data['items'];
  1373. }
  1374. else
  1375. {
  1376. return array();
  1377. }
  1378. }
  1379. }
  1380. class SimplePie_Item
  1381. {
  1382. var $feed;
  1383. var $data = array();
  1384. public function __construct($feed, $data)
  1385. {
  1386. $this->feed = $feed;
  1387. $this->data = $data;
  1388. }
  1389. public function __toString()
  1390. {
  1391. return md5(serialize($this->data));
  1392. }
  1393. /**
  1394. * Remove items that link back to this before destroying this object
  1395. */
  1396. public function __destruct()
  1397. {
  1398. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  1399. {
  1400. unset($this->feed);
  1401. }
  1402. }
  1403. public function get_item_tags($namespace, $tag)
  1404. {
  1405. if (isset($this->data['child'][$namespace][$tag]))
  1406. {
  1407. return $this->data['child'][$namespace][$tag];
  1408. }
  1409. else
  1410. {
  1411. return null;
  1412. }
  1413. }
  1414. public function get_base($element = array())
  1415. {
  1416. return $this->feed->get_base($element);
  1417. }
  1418. public function sanitize($data, $type, $base = '')
  1419. {
  1420. return $this->feed->sanitize($data, $type, $base);
  1421. }
  1422. public function get_feed()
  1423. {
  1424. return $this->feed;
  1425. }
  1426. public function get_id($hash = false)
  1427. {
  1428. if (!$hash)
  1429. {
  1430. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
  1431. {
  1432. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1433. }
  1434. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
  1435. {
  1436. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1437. }
  1438. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  1439. {
  1440. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1441. }
  1442. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
  1443. {
  1444. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1445. }
  1446. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
  1447. {
  1448. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1449. }
  1450. elseif (($return = $this->get_permalink()) !== null)
  1451. {
  1452. return $return;
  1453. }
  1454. elseif (($return = $this->get_title()) !== null)
  1455. {
  1456. return $return;
  1457. }
  1458. }
  1459. if ($this->get_permalink() !== null || $this->get_title() !== null)
  1460. {
  1461. return md5($this->get_permalink() . $this->get_title());
  1462. }
  1463. else
  1464. {
  1465. return md5(serialize($this->data));
  1466. }
  1467. }
  1468. public function get_title()
  1469. {
  1470. if (!isset($this->data['title']))
  1471. {
  1472. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  1473. {
  1474. $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1475. }
  1476. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  1477. {
  1478. $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1479. }
  1480. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  1481. {
  1482. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1483. }
  1484. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  1485. {
  1486. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1487. }
  1488. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  1489. {
  1490. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1491. }
  1492. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  1493. {
  1494. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1495. }
  1496. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  1497. {
  1498. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1499. }
  1500. else
  1501. {
  1502. $this->data['title'] = null;
  1503. }
  1504. }
  1505. return $this->data['title'];
  1506. }
  1507. public function get_description($description_only = false)
  1508. {
  1509. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
  1510. {
  1511. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1512. }
  1513. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
  1514. {
  1515. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1516. }
  1517. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  1518. {
  1519. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1520. }
  1521. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  1522. {
  1523. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1524. }
  1525. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  1526. {
  1527. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1528. }
  1529. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  1530. {
  1531. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1532. }
  1533. elseif (!$description_only)
  1534. {
  1535. return $this->get_content(true);
  1536. }
  1537. else
  1538. {
  1539. return null;
  1540. }
  1541. }
  1542. public function get_content($content_only = false)
  1543. {
  1544. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
  1545. {
  1546. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_content_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1547. }
  1548. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
  1549. {
  1550. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1551. }
  1552. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
  1553. {
  1554. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  1555. }
  1556. elseif (!$content_only)
  1557. {
  1558. return $this->get_description(true);
  1559. }
  1560. else
  1561. {
  1562. return null;
  1563. }
  1564. }
  1565. public function get_category($key = 0)
  1566. {
  1567. $categories = $this->get_categories();
  1568. if (isset($categories[$key]))
  1569. {
  1570. return $categories[$key];
  1571. }
  1572. else
  1573. {
  1574. return null;
  1575. }
  1576. }
  1577. public function get_categories()
  1578. {
  1579. $categories = array();
  1580. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  1581. {
  1582. $term = null;
  1583. $scheme = null;
  1584. $label = null;
  1585. if (isset($category['attribs']['']['term']))
  1586. {
  1587. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  1588. }
  1589. if (isset($category['attribs']['']['scheme']))
  1590. {
  1591. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  1592. }
  1593. if (isset($category['attribs']['']['label']))
  1594. {
  1595. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  1596. }
  1597. $categories[] = new $this->feed->category_class($term, $scheme, $label);
  1598. }
  1599. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  1600. {
  1601. // This is really the label, but keep this as the term also for BC.
  1602. // Label will also work on retrieving because that falls back to term.
  1603. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1604. if (isset($category['attribs']['']['domain']))
  1605. {
  1606. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  1607. }
  1608. else
  1609. {
  1610. $scheme = null;
  1611. }
  1612. $categories[] = new $this->feed->category_class($term, $scheme, null);
  1613. }
  1614. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  1615. {
  1616. $categories[] = new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  1617. }
  1618. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  1619. {
  1620. $categories[] = new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  1621. }
  1622. if (!empty($categories))
  1623. {
  1624. return SimplePie_Misc::array_unique($categories);
  1625. }
  1626. else
  1627. {
  1628. return null;
  1629. }
  1630. }
  1631. public function get_author($key = 0)
  1632. {
  1633. $authors = $this->get_authors();
  1634. if (isset($authors[$key]))
  1635. {
  1636. return $authors[$key];
  1637. }
  1638. else
  1639. {
  1640. return null;
  1641. }
  1642. }
  1643. public function get_contributor($key = 0)
  1644. {
  1645. $contributors = $this->get_contributors();
  1646. if (isset($contributors[$key]))
  1647. {
  1648. return $contributors[$key];
  1649. }
  1650. else
  1651. {
  1652. return null;
  1653. }
  1654. }
  1655. public function get_contributors()
  1656. {
  1657. $contributors = array();
  1658. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  1659. {
  1660. $name = null;
  1661. $uri = null;
  1662. $email = null;
  1663. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  1664. {
  1665. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1666. }
  1667. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  1668. {
  1669. $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
  1670. }
  1671. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  1672. {
  1673. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1674. }
  1675. if ($name !== null || $email !== null || $uri !== null)
  1676. {
  1677. $contributors[] = new $this->feed->author_class($name, $uri, $email);
  1678. }
  1679. }
  1680. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  1681. {
  1682. $name = null;
  1683. $url = null;
  1684. $email = null;
  1685. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  1686. {
  1687. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1688. }
  1689. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  1690. {
  1691. $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
  1692. }
  1693. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  1694. {
  1695. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1696. }
  1697. if ($name !== null || $email !== null || $url !== null)
  1698. {
  1699. $contributors[] = new $this->feed->author_class($name, $url, $email);
  1700. }
  1701. }
  1702. if (!empty($contributors))
  1703. {
  1704. return SimplePie_Misc::array_unique($contributors);
  1705. }
  1706. else
  1707. {
  1708. return null;
  1709. }
  1710. }
  1711. public function get_authors()
  1712. {
  1713. $authors = array();
  1714. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  1715. {
  1716. $name = null;
  1717. $uri = null;
  1718. $email = null;
  1719. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  1720. {
  1721. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1722. }
  1723. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  1724. {
  1725. $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
  1726. }
  1727. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  1728. {
  1729. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1730. }
  1731. if ($name !== null || $email !== null || $uri !== null)
  1732. {
  1733. $authors[] = new $this->feed->author_class($name, $uri, $email);
  1734. }
  1735. }
  1736. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  1737. {
  1738. $name = null;
  1739. $url = null;
  1740. $email = null;
  1741. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  1742. {
  1743. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1744. }
  1745. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  1746. {
  1747. $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
  1748. }
  1749. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  1750. {
  1751. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1752. }
  1753. if ($name !== null || $email !== null || $url !== null)
  1754. {
  1755. $authors[] = new $this->feed->author_class($name, $url, $email);
  1756. }
  1757. }
  1758. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
  1759. {
  1760. $authors[] = new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  1761. }
  1762. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  1763. {
  1764. $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  1765. }
  1766. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  1767. {
  1768. $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  1769. }
  1770. if (!empty($authors))
  1771. {
  1772. return SimplePie_Misc::array_unique($authors);
  1773. }
  1774. elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
  1775. {
  1776. return $authors;
  1777. }
  1778. elseif ($authors = $this->feed->get_authors())
  1779. {
  1780. return $authors;
  1781. }
  1782. else
  1783. {
  1784. return null;
  1785. }
  1786. }
  1787. public function get_copyright()
  1788. {
  1789. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  1790. {
  1791. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  1792. }
  1793. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  1794. {
  1795. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1796. }
  1797. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  1798. {
  1799. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1800. }
  1801. else
  1802. {
  1803. return null;
  1804. }
  1805. }
  1806. public function get_date($date_format = 'j F Y, g:i a')
  1807. {
  1808. if (!isset($this->data['date']))
  1809. {
  1810. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
  1811. {
  1812. $this->data['date']['raw'] = $return[0]['data'];
  1813. }
  1814. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
  1815. {
  1816. $this->data['date']['raw'] = $return[0]['data'];
  1817. }
  1818. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
  1819. {
  1820. $this->data['date']['raw'] = $return[0]['data'];
  1821. }
  1822. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
  1823. {
  1824. $this->data['date']['raw'] = $return[0]['data'];
  1825. }
  1826. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
  1827. {
  1828. $this->data['date']['raw'] = $return[0]['data'];
  1829. }
  1830. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
  1831. {
  1832. $this->data['date']['raw'] = $return[0]['data'];
  1833. }
  1834. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
  1835. {
  1836. $this->data['date']['raw'] = $return[0]['data'];
  1837. }
  1838. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
  1839. {
  1840. $this->data['date']['raw'] = $return[0]['data'];
  1841. }
  1842. if (!empty($this->data['date']['raw']))
  1843. {
  1844. $parser = SimplePie_Parse_Date::get();
  1845. $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
  1846. }
  1847. else
  1848. {
  1849. $this->data['date'] = null;
  1850. }
  1851. }
  1852. if ($this->data['date'])
  1853. {
  1854. $date_format = (string) $date_format;
  1855. switch ($date_format)
  1856. {
  1857. case '':
  1858. return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
  1859. case 'U':
  1860. return $this->data['date']['parsed'];
  1861. default:
  1862. return date($date_format, $this->data['date']['parsed']);
  1863. }
  1864. }
  1865. else
  1866. {
  1867. return null;
  1868. }
  1869. }
  1870. public function get_local_date($date_format = '%c')
  1871. {
  1872. if (!$date_format)
  1873. {
  1874. return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
  1875. }
  1876. elseif (($date = $this->get_date('U')) !== null)
  1877. {
  1878. return strftime($date_format, $date);
  1879. }
  1880. else
  1881. {
  1882. return null;
  1883. }
  1884. }
  1885. public function get_permalink()
  1886. {
  1887. $link = $this->get_link();
  1888. $enclosure = $this->get_enclosure(0);
  1889. if ($link !== null)
  1890. {
  1891. return $link;
  1892. }
  1893. elseif ($enclosure !== null)
  1894. {
  1895. return $enclosure->get_link();
  1896. }
  1897. else
  1898. {
  1899. return null;
  1900. }
  1901. }
  1902. public function get_link($key = 0, $rel = 'alternate')
  1903. {
  1904. $links = $this->get_links($rel);
  1905. if ($links[$key] !== null)
  1906. {
  1907. return $links[$key];
  1908. }
  1909. else
  1910. {
  1911. return null;
  1912. }
  1913. }
  1914. public function get_links($rel = 'alternate')
  1915. {
  1916. if (!isset($this->data['links']))
  1917. {
  1918. $this->data['links'] = array();
  1919. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  1920. {
  1921. if (isset($link['attribs']['']['href']))
  1922. {
  1923. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  1924. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  1925. }
  1926. }
  1927. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  1928. {
  1929. if (isset($link['attribs']['']['href']))
  1930. {
  1931. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  1932. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  1933. }
  1934. }
  1935. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  1936. {
  1937. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  1938. }
  1939. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  1940. {
  1941. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  1942. }
  1943. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  1944. {
  1945. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  1946. }
  1947. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  1948. {
  1949. if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
  1950. {
  1951. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  1952. }
  1953. }
  1954. $keys = array_keys($this->data['links']);
  1955. foreach ($keys as $key)
  1956. {
  1957. if (SimplePie_Misc::is_isegment_nz_nc($key))
  1958. {
  1959. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  1960. {
  1961. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  1962. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  1963. }
  1964. else
  1965. {
  1966. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  1967. }
  1968. }
  1969. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  1970. {
  1971. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  1972. }
  1973. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  1974. }
  1975. }
  1976. if (isset($this->data['links'][$rel]))
  1977. {
  1978. return $this->data['links'][$rel];
  1979. }
  1980. else
  1981. {
  1982. return null;
  1983. }
  1984. }
  1985. /**
  1986. * @todo Add ability to prefer one type of content over another (in a media group).
  1987. */
  1988. public function get_enclosure($key = 0, $prefer = null)
  1989. {
  1990. $enclosures = $this->get_enclosures();
  1991. if (isset($enclosures[$key]))
  1992. {
  1993. return $enclosures[$key];
  1994. }
  1995. else
  1996. {
  1997. return null;
  1998. }
  1999. }
  2000. /**
  2001. * Grabs all available enclosures (podcasts, etc.)
  2002. *
  2003. * Supports the <enclosure> RSS tag.
  2004. *
  2005. * At this point, we're pretty much assuming that all enclosures for an item are the same content. Anything else is too complicated to properly support.
  2006. *
  2007. * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
  2008. * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
  2009. */
  2010. public function get_enclosures()
  2011. {
  2012. if (!isset($this->data['enclosures']))
  2013. {
  2014. $this->data['enclosures'] = array();
  2015. // Elements
  2016. $captions_parent = null;
  2017. $categories_parent = null;
  2018. $copyrights_parent = null;
  2019. $credits_parent = null;
  2020. $description_parent = null;
  2021. $duration_parent = null;
  2022. $hashes_parent = null;
  2023. $keywords_parent = null;
  2024. $player_parent = null;
  2025. $ratings_parent = null;
  2026. $restrictions_parent = null;
  2027. $thumbnails_parent = null;
  2028. $title_parent = null;
  2029. // Let's do the channel and item-level ones first, and just re-use them if we need to.
  2030. $parent = $this->get_feed();
  2031. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  2032. {
  2033. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  2034. {
  2035. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2036. if (isset($link['attribs']['']['type']))
  2037. {
  2038. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  2039. }
  2040. else
  2041. {
  2042. $type = null;
  2043. }
  2044. if (isset($link['attribs']['']['length']))
  2045. {
  2046. $length = ceil($link['attribs']['']['length']);
  2047. }
  2048. else
  2049. {
  2050. $length = null;
  2051. }
  2052. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  2053. $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length);
  2054. }
  2055. }
  2056. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  2057. {
  2058. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  2059. {
  2060. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2061. if (isset($link['attribs']['']['type']))
  2062. {
  2063. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  2064. }
  2065. else
  2066. {
  2067. $type = null;
  2068. }
  2069. if (isset($link['attribs']['']['length']))
  2070. {
  2071. $length = ceil($link['attribs']['']['length']);
  2072. }
  2073. else
  2074. {
  2075. $length = null;
  2076. }
  2077. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  2078. $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length);
  2079. }
  2080. }
  2081. if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
  2082. {
  2083. if (isset($enclosure[0]['attribs']['']['url']))
  2084. {
  2085. $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
  2086. if (isset($enclosure[0]['attribs']['']['type']))
  2087. {
  2088. $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  2089. }
  2090. else
  2091. {
  2092. $type = null;
  2093. }
  2094. if (isset($enclosure[0]['attribs']['']['length']))
  2095. {
  2096. $length = ceil($enclosure[0]['attribs']['']['length']);
  2097. }
  2098. else
  2099. {
  2100. $length = null;
  2101. }
  2102. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  2103. $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length);
  2104. }
  2105. }
  2106. $this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures']));
  2107. }
  2108. if (!empty($this->data['enclosures']))
  2109. {
  2110. return $this->data['enclosures'];
  2111. }
  2112. else
  2113. {
  2114. return null;
  2115. }
  2116. }
  2117. public function get_source()
  2118. {
  2119. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
  2120. {
  2121. return new $this->feed->source_class($this, $return[0]);
  2122. }
  2123. else
  2124. {
  2125. return null;
  2126. }
  2127. }
  2128. }
  2129. class SimplePie_Source
  2130. {
  2131. var $item;
  2132. var $data = array();
  2133. public function __construct($item, $data)
  2134. {
  2135. $this->item = $item;
  2136. $this->data = $data;
  2137. }
  2138. public function __toString()
  2139. {
  2140. return md5(serialize($this->data));
  2141. }
  2142. public function get_source_tags($namespace, $tag)
  2143. {
  2144. if (isset($this->data['child'][$namespace][$tag]))
  2145. {
  2146. return $this->data['child'][$namespace][$tag];
  2147. }
  2148. else
  2149. {
  2150. return null;
  2151. }
  2152. }
  2153. public function get_base($element = array())
  2154. {
  2155. return $this->item->get_base($element);
  2156. }
  2157. public function sanitize($data, $type, $base = '')
  2158. {
  2159. return $this->item->sanitize($data, $type, $base);
  2160. }
  2161. public function get_item()
  2162. {
  2163. return $this->item;
  2164. }
  2165. public function get_title()
  2166. {
  2167. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  2168. {
  2169. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  2170. }
  2171. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  2172. {
  2173. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  2174. }
  2175. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  2176. {
  2177. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2178. }
  2179. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  2180. {
  2181. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2182. }
  2183. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  2184. {
  2185. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2186. }
  2187. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  2188. {
  2189. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2190. }
  2191. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  2192. {
  2193. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2194. }
  2195. else
  2196. {
  2197. return null;
  2198. }
  2199. }
  2200. public function get_category($key = 0)
  2201. {
  2202. $categories = $this->get_categories();
  2203. if (isset($categories[$key]))
  2204. {
  2205. return $categories[$key];
  2206. }
  2207. else
  2208. {
  2209. return null;
  2210. }
  2211. }
  2212. public function get_categories()
  2213. {
  2214. $categories = array();
  2215. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  2216. {
  2217. $term = null;
  2218. $scheme = null;
  2219. $label = null;
  2220. if (isset($category['attribs']['']['term']))
  2221. {
  2222. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  2223. }
  2224. if (isset($category['attribs']['']['scheme']))
  2225. {
  2226. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  2227. }
  2228. if (isset($category['attribs']['']['label']))
  2229. {
  2230. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  2231. }
  2232. $categories[] = new $this->item->feed->category_class($term, $scheme, $label);
  2233. }
  2234. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  2235. {
  2236. // This is really the label, but keep this as the term also for BC.
  2237. // Label will also work on retrieving because that falls back to term.
  2238. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2239. if (isset($category['attribs']['']['domain']))
  2240. {
  2241. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  2242. }
  2243. else
  2244. {
  2245. $scheme = null;
  2246. }
  2247. $categories[] = new $this->item->feed->category_class($term, $scheme, null);
  2248. }
  2249. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  2250. {
  2251. $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  2252. }
  2253. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  2254. {
  2255. $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  2256. }
  2257. if (!empty($categories))
  2258. {
  2259. return SimplePie_Misc::array_unique($categories);
  2260. }
  2261. else
  2262. {
  2263. return null;
  2264. }
  2265. }
  2266. public function get_author($key = 0)
  2267. {
  2268. $authors = $this->get_authors();
  2269. if (isset($authors[$key]))
  2270. {
  2271. return $authors[$key];
  2272. }
  2273. else
  2274. {
  2275. return null;
  2276. }
  2277. }
  2278. public function get_authors()
  2279. {
  2280. $authors = array();
  2281. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  2282. {
  2283. $name = null;
  2284. $uri = null;
  2285. $email = null;
  2286. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  2287. {
  2288. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2289. }
  2290. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  2291. {
  2292. $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
  2293. }
  2294. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  2295. {
  2296. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2297. }
  2298. if ($name !== null || $email !== null || $uri !== null)
  2299. {
  2300. $authors[] = new $this->item->feed->author_class($name, $uri, $email);
  2301. }
  2302. }
  2303. if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  2304. {
  2305. $name = null;
  2306. $url = null;
  2307. $email = null;
  2308. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  2309. {
  2310. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2311. }
  2312. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  2313. {
  2314. $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
  2315. }
  2316. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  2317. {
  2318. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2319. }
  2320. if ($name !== null || $email !== null || $url !== null)
  2321. {
  2322. $authors[] = new $this->item->feed->author_class($name, $url, $email);
  2323. }
  2324. }
  2325. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  2326. {
  2327. $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  2328. }
  2329. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  2330. {
  2331. $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
  2332. }
  2333. if (!empty($authors))
  2334. {
  2335. return SimplePie_Misc::array_unique($authors);
  2336. }
  2337. else
  2338. {
  2339. return null;
  2340. }
  2341. }
  2342. public function get_contributor($key = 0)
  2343. {
  2344. $contributors = $this->get_contributors();
  2345. if (isset($contributors[$key]))
  2346. {
  2347. return $contributors[$key];
  2348. }
  2349. else
  2350. {
  2351. return null;
  2352. }
  2353. }
  2354. public function get_contributors()
  2355. {
  2356. $contributors = array();
  2357. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  2358. {
  2359. $name = null;
  2360. $uri = null;
  2361. $email = null;
  2362. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  2363. {
  2364. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2365. }
  2366. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  2367. {
  2368. $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
  2369. }
  2370. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  2371. {
  2372. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2373. }
  2374. if ($name !== null || $email !== null || $uri !== null)
  2375. {
  2376. $contributors[] = new $this->item->feed->author_class($name, $uri, $email);
  2377. }
  2378. }
  2379. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  2380. {
  2381. $name = null;
  2382. $url = null;
  2383. $email = null;
  2384. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  2385. {
  2386. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2387. }
  2388. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  2389. {
  2390. $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
  2391. }
  2392. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  2393. {
  2394. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2395. }
  2396. if ($name !== null || $email !== null || $url !== null)
  2397. {
  2398. $contributors[] = new $this->item->feed->author_class($name, $url, $email);
  2399. }
  2400. }
  2401. if (!empty($contributors))
  2402. {
  2403. return SimplePie_Misc::array_unique($contributors);
  2404. }
  2405. else
  2406. {
  2407. return null;
  2408. }
  2409. }
  2410. public function get_link($key = 0, $rel = 'alternate')
  2411. {
  2412. $links = $this->get_links($rel);
  2413. if (isset($links[$key]))
  2414. {
  2415. return $links[$key];
  2416. }
  2417. else
  2418. {
  2419. return null;
  2420. }
  2421. }
  2422. /**
  2423. * Added for parity between the parent-level and the item/entry-level.
  2424. */
  2425. public function get_permalink()
  2426. {
  2427. return $this->get_link(0);
  2428. }
  2429. public function get_links($rel = 'alternate')
  2430. {
  2431. if (!isset($this->data['links']))
  2432. {
  2433. $this->data['links'] = array();
  2434. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  2435. {
  2436. foreach ($links as $link)
  2437. {
  2438. if (isset($link['attribs']['']['href']))
  2439. {
  2440. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2441. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2442. }
  2443. }
  2444. }
  2445. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  2446. {
  2447. foreach ($links as $link)
  2448. {
  2449. if (isset($link['attribs']['']['href']))
  2450. {
  2451. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2452. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2453. }
  2454. }
  2455. }
  2456. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  2457. {
  2458. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2459. }
  2460. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  2461. {
  2462. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2463. }
  2464. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  2465. {
  2466. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2467. }
  2468. $keys = array_keys($this->data['links']);
  2469. foreach ($keys as $key)
  2470. {
  2471. if (SimplePie_Misc::is_isegment_nz_nc($key))
  2472. {
  2473. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  2474. {
  2475. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  2476. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  2477. }
  2478. else
  2479. {
  2480. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  2481. }
  2482. }
  2483. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  2484. {
  2485. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  2486. }
  2487. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  2488. }
  2489. }
  2490. if (isset($this->data['links'][$rel]))
  2491. {
  2492. return $this->data['links'][$rel];
  2493. }
  2494. else
  2495. {
  2496. return null;
  2497. }
  2498. }
  2499. public function get_description()
  2500. {
  2501. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  2502. {
  2503. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  2504. }
  2505. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  2506. {
  2507. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  2508. }
  2509. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  2510. {
  2511. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2512. }
  2513. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  2514. {
  2515. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2516. }
  2517. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  2518. {
  2519. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2520. }
  2521. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  2522. {
  2523. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2524. }
  2525. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  2526. {
  2527. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2528. }
  2529. else
  2530. {
  2531. return null;
  2532. }
  2533. }
  2534. public function get_copyright()
  2535. {
  2536. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  2537. {
  2538. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  2539. }
  2540. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  2541. {
  2542. return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
  2543. }
  2544. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  2545. {
  2546. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2547. }
  2548. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  2549. {
  2550. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2551. }
  2552. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  2553. {
  2554. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2555. }
  2556. else
  2557. {
  2558. return null;
  2559. }
  2560. }
  2561. public function get_language()
  2562. {
  2563. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  2564. {
  2565. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2566. }
  2567. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  2568. {
  2569. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2570. }
  2571. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  2572. {
  2573. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2574. }
  2575. elseif (isset($this->data['xml_lang']))
  2576. {
  2577. return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2578. }
  2579. else
  2580. {
  2581. return null;
  2582. }
  2583. }
  2584. public function get_image_url()
  2585. {
  2586. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  2587. {
  2588. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2589. }
  2590. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  2591. {
  2592. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2593. }
  2594. else
  2595. {
  2596. return null;
  2597. }
  2598. }
  2599. }
  2600. class SimplePie_Author
  2601. {
  2602. var $name;
  2603. var $link;
  2604. var $email;
  2605. // Constructor, used to input the data
  2606. public function __construct($name = null, $link = null, $email = null)
  2607. {
  2608. $this->name = $name;
  2609. $this->link = $link;
  2610. $this->email = $email;
  2611. }
  2612. public function __toString()
  2613. {
  2614. // There is no $this->data here
  2615. return md5(serialize($this));
  2616. }
  2617. public function get_name()
  2618. {
  2619. if ($this->name !== null)
  2620. {
  2621. return $this->name;
  2622. }
  2623. else
  2624. {
  2625. return null;
  2626. }
  2627. }
  2628. public function get_link()
  2629. {
  2630. if ($this->link !== null)
  2631. {
  2632. return $this->link;
  2633. }
  2634. else
  2635. {
  2636. return null;
  2637. }
  2638. }
  2639. public function get_email()
  2640. {
  2641. if ($this->email !== null)
  2642. {
  2643. return $this->email;
  2644. }
  2645. else
  2646. {
  2647. return null;
  2648. }
  2649. }
  2650. }
  2651. class SimplePie_Category
  2652. {
  2653. var $term;
  2654. var $scheme;
  2655. var $label;
  2656. // Constructor, used to input the data
  2657. public function __construct($term = null, $scheme = null, $label = null)
  2658. {
  2659. $this->term = $term;
  2660. $this->scheme = $scheme;
  2661. $this->label = $label;
  2662. }
  2663. public function __toString()
  2664. {
  2665. // There is no $this->data here
  2666. return md5(serialize($this));
  2667. }
  2668. public function get_term()
  2669. {
  2670. if ($this->term !== null)
  2671. {
  2672. return $this->term;
  2673. }
  2674. else
  2675. {
  2676. return null;
  2677. }
  2678. }
  2679. public function get_scheme()
  2680. {
  2681. if ($this->scheme !== null)
  2682. {
  2683. return $this->scheme;
  2684. }
  2685. else
  2686. {
  2687. return null;
  2688. }
  2689. }
  2690. public function get_label()
  2691. {
  2692. if ($this->label !== null)
  2693. {
  2694. return $this->label;
  2695. }
  2696. else
  2697. {
  2698. return $this->get_term();
  2699. }
  2700. }
  2701. }
  2702. class SimplePie_Enclosure
  2703. {
  2704. var $length;
  2705. var $link;
  2706. var $type;
  2707. // Constructor, used to input the data
  2708. public function __construct($link = null, $type = null, $length = null)
  2709. {
  2710. $this->length = $length;
  2711. $this->link = $link;
  2712. $this->type = $type;
  2713. if (class_exists('idna_convert'))
  2714. {
  2715. $idn = new idna_convert();
  2716. $parsed = SimplePie_Misc::parse_url($link);
  2717. $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
  2718. }
  2719. }
  2720. public function __toString()
  2721. {
  2722. // There is no $this->data here
  2723. return md5(serialize($this));
  2724. }
  2725. public function get_length()
  2726. {
  2727. if ($this->length !== null)
  2728. {
  2729. return $this->length;
  2730. }
  2731. else
  2732. {
  2733. return null;
  2734. }
  2735. }
  2736. public function get_link()
  2737. {
  2738. if ($this->link !== null)
  2739. {
  2740. return urldecode($this->link);
  2741. }
  2742. else
  2743. {
  2744. return null;
  2745. }
  2746. }
  2747. public function get_type()
  2748. {
  2749. if ($this->type !== null)
  2750. {
  2751. return $this->type;
  2752. }
  2753. else
  2754. {
  2755. return null;
  2756. }
  2757. }
  2758. }
  2759. class SimplePie_Misc
  2760. {
  2761. public static function absolutize_url($relative, $base)
  2762. {
  2763. $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
  2764. return $iri->get_iri();
  2765. }
  2766. public static function remove_dot_segments($input)
  2767. {
  2768. $output = '';
  2769. while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
  2770. {
  2771. // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
  2772. if (strpos($input, '../') === 0)
  2773. {
  2774. $input = substr($input, 3);
  2775. }
  2776. elseif (strpos($input, './') === 0)
  2777. {
  2778. $input = substr($input, 2);
  2779. }
  2780. // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
  2781. elseif (strpos($input, '/./') === 0)
  2782. {
  2783. $input = substr_replace($input, '/', 0, 3);
  2784. }
  2785. elseif ($input === '/.')
  2786. {
  2787. $input = '/';
  2788. }
  2789. // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
  2790. elseif (strpos($input, '/../') === 0)
  2791. {
  2792. $input = substr_replace($input, '/', 0, 4);
  2793. $output = substr_replace($output, '', strrpos($output, '/'));
  2794. }
  2795. elseif ($input === '/..')
  2796. {
  2797. $input = '/';
  2798. $output = substr_replace($output, '', strrpos($output, '/'));
  2799. }
  2800. // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
  2801. elseif ($input === '.' || $input === '..')
  2802. {
  2803. $input = '';
  2804. }
  2805. // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
  2806. elseif (($pos = strpos($input, '/', 1)) !== false)
  2807. {
  2808. $output .= substr($input, 0, $pos);
  2809. $input = substr_replace($input, '', 0, $pos);
  2810. }
  2811. else
  2812. {
  2813. $output .= $input;
  2814. $input = '';
  2815. }
  2816. }
  2817. return $output . $input;
  2818. }
  2819. public static function get_element($realname, $string)
  2820. {
  2821. $return = array();
  2822. $name = preg_quote($realname, '/');
  2823. if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
  2824. {
  2825. for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
  2826. {
  2827. $return[$i]['tag'] = $realname;
  2828. $return[$i]['full'] = $matches[$i][0][0];
  2829. $return[$i]['offset'] = $matches[$i][0][1];
  2830. if (strlen($matches[$i][3][0]) <= 2)
  2831. {
  2832. $return[$i]['self_closing'] = true;
  2833. }
  2834. else
  2835. {
  2836. $return[$i]['self_closing'] = false;
  2837. $return[$i]['content'] = $matches[$i][4][0];
  2838. }
  2839. $return[$i]['attribs'] = array();
  2840. if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER))
  2841. {
  2842. for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
  2843. {
  2844. if (count($attribs[$j]) === 2)
  2845. {
  2846. $attribs[$j][2] = $attribs[$j][1];
  2847. }
  2848. $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
  2849. }
  2850. }
  2851. }
  2852. }
  2853. return $return;
  2854. }
  2855. public static function element_implode($element)
  2856. {
  2857. $full = "<$element[tag]";
  2858. foreach ($element['attribs'] as $key => $value)
  2859. {
  2860. $key = strtolower($key);
  2861. $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
  2862. }
  2863. if ($element['self_closing'])
  2864. {
  2865. $full .= ' />';
  2866. }
  2867. else
  2868. {
  2869. $full .= ">$element[content]</$element[tag]>";
  2870. }
  2871. return $full;
  2872. }
  2873. public static function error($message, $level, $file, $line)
  2874. {
  2875. if ((ini_get('error_reporting') & $level) > 0)
  2876. {
  2877. switch ($level)
  2878. {
  2879. case E_USER_ERROR:
  2880. $note = 'PHP Error';
  2881. break;
  2882. case E_USER_WARNING:
  2883. $note = 'PHP Warning';
  2884. break;
  2885. case E_USER_NOTICE:
  2886. $note = 'PHP Notice';
  2887. break;
  2888. default:
  2889. $note = 'Unknown Error';
  2890. break;
  2891. }
  2892. $log_error = true;
  2893. if (!function_exists('error_log'))
  2894. {
  2895. $log_error = false;
  2896. }
  2897. $log_file = @ini_get('error_log');
  2898. if (!empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file))
  2899. {
  2900. $log_error = false;
  2901. }
  2902. if ($log_error)
  2903. {
  2904. @error_log("$note: $message in $file on line $line", 0);
  2905. }
  2906. }
  2907. return $message;
  2908. }
  2909. public static function parse_url($url)
  2910. {
  2911. $iri = new SimplePie_IRI($url);
  2912. return array(
  2913. 'scheme' => (string) $iri->get_scheme(),
  2914. 'authority' => (string) $iri->get_authority(),
  2915. 'path' => (string) $iri->get_path(),
  2916. 'query' => (string) $iri->get_query(),
  2917. 'fragment' => (string) $iri->get_fragment()
  2918. );
  2919. }
  2920. public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
  2921. {
  2922. $iri = new SimplePie_IRI('');
  2923. $iri->set_scheme($scheme);
  2924. $iri->set_authority($authority);
  2925. $iri->set_path($path);
  2926. $iri->set_query($query);
  2927. $iri->set_fragment($fragment);
  2928. return $iri->get_iri();
  2929. }
  2930. public static function normalize_url($url)
  2931. {
  2932. $iri = new SimplePie_IRI($url);
  2933. return $iri->get_iri();
  2934. }
  2935. public static function percent_encoding_normalization($match)
  2936. {
  2937. $integer = hexdec($match[1]);
  2938. if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
  2939. {
  2940. return chr($integer);
  2941. }
  2942. else
  2943. {
  2944. return strtoupper($match[0]);
  2945. }
  2946. }
  2947. public static function get_curl_version()
  2948. {
  2949. if (is_array($curl = curl_version()))
  2950. {
  2951. $curl = $curl['version'];
  2952. }
  2953. elseif (substr($curl, 0, 5) === 'curl/')
  2954. {
  2955. $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
  2956. }
  2957. elseif (substr($curl, 0, 8) === 'libcurl/')
  2958. {
  2959. $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
  2960. }
  2961. else
  2962. {
  2963. $curl = 0;
  2964. }
  2965. return $curl;
  2966. }
  2967. public static function is_subclass_of($class1, $class2)
  2968. {
  2969. if (func_num_args() !== 2)
  2970. {
  2971. trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING);
  2972. }
  2973. elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1))
  2974. {
  2975. return is_subclass_of($class1, $class2);
  2976. }
  2977. elseif (is_string($class1) && is_string($class2))
  2978. {
  2979. if (class_exists($class1))
  2980. {
  2981. if (class_exists($class2))
  2982. {
  2983. $class2 = strtolower($class2);
  2984. while ($class1 = strtolower(get_parent_class($class1)))
  2985. {
  2986. if ($class1 === $class2)
  2987. {
  2988. return true;
  2989. }
  2990. }
  2991. }
  2992. }
  2993. else
  2994. {
  2995. trigger_error('Unknown class passed as parameter', E_USER_WARNNG);
  2996. }
  2997. }
  2998. return false;
  2999. }
  3000. public static function parse_date($dt)
  3001. {
  3002. $parser = SimplePie_Parse_Date::get();
  3003. return $parser->parse($dt);
  3004. }
  3005. /**
  3006. * Decode HTML entities
  3007. *
  3008. * @param string $data Input data
  3009. * @return string Output data
  3010. */
  3011. public static function entities_decode($data)
  3012. {
  3013. $decoder = new SimplePie_Decode_HTML_Entities($data);
  3014. return $decoder->parse();
  3015. }
  3016. /**
  3017. * Remove RFC822 comments
  3018. *
  3019. * @param string $data Data to strip comments from
  3020. * @return string Comment stripped string
  3021. */
  3022. public static function uncomment_rfc822($string)
  3023. {
  3024. $string = (string) $string;
  3025. $position = 0;
  3026. $length = strlen($string);
  3027. $depth = 0;
  3028. $output = '';
  3029. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  3030. {
  3031. $output .= substr($string, $position, $pos - $position);
  3032. $position = $pos + 1;
  3033. if ($string[$pos - 1] !== '\\')
  3034. {
  3035. $depth++;
  3036. while ($depth && $position < $length)
  3037. {
  3038. $position += strcspn($string, '()', $position);
  3039. if ($string[$position - 1] === '\\')
  3040. {
  3041. $position++;
  3042. continue;
  3043. }
  3044. elseif (isset($string[$position]))
  3045. {
  3046. switch ($string[$position])
  3047. {
  3048. case '(':
  3049. $depth++;
  3050. break;
  3051. case ')':
  3052. $depth--;
  3053. break;
  3054. }
  3055. $position++;
  3056. }
  3057. else
  3058. {
  3059. break;
  3060. }
  3061. }
  3062. }
  3063. else
  3064. {
  3065. $output .= '(';
  3066. }
  3067. }
  3068. $output .= substr($string, $position);
  3069. return $output;
  3070. }
  3071. public static function parse_mime($mime)
  3072. {
  3073. if (($pos = strpos($mime, ';')) === false)
  3074. {
  3075. return trim($mime);
  3076. }
  3077. else
  3078. {
  3079. return trim(substr($mime, 0, $pos));
  3080. }
  3081. }
  3082. public static function htmlspecialchars_decode($string, $quote_style)
  3083. {
  3084. if (function_exists('htmlspecialchars_decode'))
  3085. {
  3086. return htmlspecialchars_decode($string, $quote_style);
  3087. }
  3088. else
  3089. {
  3090. return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
  3091. }
  3092. }
  3093. public static function atom_03_construct_type($attribs)
  3094. {
  3095. if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
  3096. {
  3097. $mode = SIMPLEPIE_CONSTRUCT_BASE64;
  3098. }
  3099. else
  3100. {
  3101. $mode = SIMPLEPIE_CONSTRUCT_NONE;
  3102. }
  3103. if (isset($attribs['']['type']))
  3104. {
  3105. switch (strtolower(trim($attribs['']['type'])))
  3106. {
  3107. case 'text':
  3108. case 'text/plain':
  3109. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  3110. case 'html':
  3111. case 'text/html':
  3112. return SIMPLEPIE_CONSTRUCT_HTML | $mode;
  3113. case 'xhtml':
  3114. case 'application/xhtml+xml':
  3115. return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
  3116. default:
  3117. return SIMPLEPIE_CONSTRUCT_NONE | $mode;
  3118. }
  3119. }
  3120. else
  3121. {
  3122. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  3123. }
  3124. }
  3125. public static function atom_10_construct_type($attribs)
  3126. {
  3127. if (isset($attribs['']['type']))
  3128. {
  3129. switch (strtolower(trim($attribs['']['type'])))
  3130. {
  3131. case 'text':
  3132. return SIMPLEPIE_CONSTRUCT_TEXT;
  3133. case 'html':
  3134. return SIMPLEPIE_CONSTRUCT_HTML;
  3135. case 'xhtml':
  3136. return SIMPLEPIE_CONSTRUCT_XHTML;
  3137. default:
  3138. return SIMPLEPIE_CONSTRUCT_NONE;
  3139. }
  3140. }
  3141. return SIMPLEPIE_CONSTRUCT_TEXT;
  3142. }
  3143. public static function atom_10_content_construct_type($attribs)
  3144. {
  3145. if (isset($attribs['']['type']))
  3146. {
  3147. $type = strtolower(trim($attribs['']['type']));
  3148. switch ($type)
  3149. {
  3150. case 'text':
  3151. return SIMPLEPIE_CONSTRUCT_TEXT;
  3152. case 'html':
  3153. return SIMPLEPIE_CONSTRUCT_HTML;
  3154. case 'xhtml':
  3155. return SIMPLEPIE_CONSTRUCT_XHTML;
  3156. }
  3157. if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
  3158. {
  3159. return SIMPLEPIE_CONSTRUCT_NONE;
  3160. }
  3161. else
  3162. {
  3163. return SIMPLEPIE_CONSTRUCT_BASE64;
  3164. }
  3165. }
  3166. else
  3167. {
  3168. return SIMPLEPIE_CONSTRUCT_TEXT;
  3169. }
  3170. }
  3171. public static function is_isegment_nz_nc($string)
  3172. {
  3173. return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
  3174. }
  3175. public static function space_seperated_tokens($string)
  3176. {
  3177. $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
  3178. $string_length = strlen($string);
  3179. $position = strspn($string, $space_characters);
  3180. $tokens = array();
  3181. while ($position < $string_length)
  3182. {
  3183. $len = strcspn($string, $space_characters, $position);
  3184. $tokens[] = substr($string, $position, $len);
  3185. $position += $len;
  3186. $position += strspn($string, $space_characters, $position);
  3187. }
  3188. return $tokens;
  3189. }
  3190. public static function array_unique($array)
  3191. {
  3192. if (version_compare(PHP_VERSION, '5.2', '>='))
  3193. {
  3194. return array_unique($array);
  3195. }
  3196. else
  3197. {
  3198. $array = (array) $array;
  3199. $new_array = array();
  3200. $new_array_strings = array();
  3201. foreach ($array as $key => $value)
  3202. {
  3203. if (is_object($value))
  3204. {
  3205. if (method_exists($value, '__toString'))
  3206. {
  3207. $cmp = $value->__toString();
  3208. }
  3209. else
  3210. {
  3211. trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR);
  3212. }
  3213. }
  3214. elseif (is_array($value))
  3215. {
  3216. $cmp = (string) reset($value);
  3217. }
  3218. else
  3219. {
  3220. $cmp = (string) $value;
  3221. }
  3222. if (!in_array($cmp, $new_array_strings))
  3223. {
  3224. $new_array[$key] = $value;
  3225. $new_array_strings[] = $cmp;
  3226. }
  3227. }
  3228. return $new_array;
  3229. }
  3230. }
  3231. /**
  3232. * Converts a unicode codepoint to a UTF-8 character
  3233. *
  3234. * @param int $codepoint Unicode codepoint
  3235. * @return string UTF-8 character
  3236. */
  3237. public static function codepoint_to_utf8($codepoint)
  3238. {
  3239. $codepoint = (int) $codepoint;
  3240. if ($codepoint < 0)
  3241. {
  3242. return false;
  3243. }
  3244. else if ($codepoint <= 0x7f)
  3245. {
  3246. return chr($codepoint);
  3247. }
  3248. else if ($codepoint <= 0x7ff)
  3249. {
  3250. return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
  3251. }
  3252. else if ($codepoint <= 0xffff)
  3253. {
  3254. return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  3255. }
  3256. else if ($codepoint <= 0x10ffff)
  3257. {
  3258. return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  3259. }
  3260. else
  3261. {
  3262. // U+FFFD REPLACEMENT CHARACTER
  3263. return "\xEF\xBF\xBD";
  3264. }
  3265. }
  3266. /**
  3267. * Re-implementation of PHP 5's stripos()
  3268. *
  3269. * Returns the numeric position of the first occurrence of needle in the
  3270. * haystack string.
  3271. *
  3272. * @param object $haystack
  3273. * @param string $needle Note that the needle may be a string of one or more
  3274. * characters. If needle is not a string, it is converted to an integer
  3275. * and applied as the ordinal value of a character.
  3276. * @param int $offset The optional offset parameter allows you to specify which
  3277. * character in haystack to start searching. The position returned is still
  3278. * relative to the beginning of haystack.
  3279. * @return bool If needle is not found, stripos() will return boolean false.
  3280. */
  3281. public static function stripos($haystack, $needle, $offset = 0)
  3282. {
  3283. if (function_exists('stripos'))
  3284. {
  3285. return stripos($haystack, $needle, $offset);
  3286. }
  3287. else
  3288. {
  3289. if (is_string($needle))
  3290. {
  3291. $needle = strtolower($needle);
  3292. }
  3293. elseif (is_int($needle) || is_bool($needle) || is_double($needle))
  3294. {
  3295. $needle = strtolower(chr($needle));
  3296. }
  3297. else
  3298. {
  3299. trigger_error('needle is not a string or an integer', E_USER_WARNING);
  3300. return false;
  3301. }
  3302. return strpos(strtolower($haystack), $needle, $offset);
  3303. }
  3304. }
  3305. /**
  3306. * Similar to parse_str()
  3307. *
  3308. * Returns an associative array of name/value pairs, where the value is an
  3309. * array of values that have used the same name
  3310. *
  3311. * @access string
  3312. * @param string $str The input string.
  3313. * @return array
  3314. */
  3315. public static function parse_str($str)
  3316. {
  3317. $return = array();
  3318. $str = explode('&', $str);
  3319. foreach ($str as $section)
  3320. {
  3321. if (strpos($section, '=') !== false)
  3322. {
  3323. list($name, $value) = explode('=', $section, 2);
  3324. $return[urldecode($name)][] = urldecode($value);
  3325. }
  3326. else
  3327. {
  3328. $return[urldecode($section)][] = null;
  3329. }
  3330. }
  3331. return $return;
  3332. }
  3333. }
  3334. /**
  3335. * Decode HTML Entities
  3336. *
  3337. * This implements HTML5 as of revision 967 (2007-06-28)
  3338. *
  3339. * @package SimplePie
  3340. */
  3341. class SimplePie_Decode_HTML_Entities
  3342. {
  3343. /**
  3344. * Data to be parsed
  3345. *
  3346. * @access private
  3347. * @var string
  3348. */
  3349. var $data = '';
  3350. /**
  3351. * Currently consumed bytes
  3352. *
  3353. * @access private
  3354. * @var string
  3355. */
  3356. var $consumed = '';
  3357. /**
  3358. * Position of the current byte being parsed
  3359. *
  3360. * @access private
  3361. * @var int
  3362. */
  3363. var $position = 0;
  3364. /**
  3365. * Create an instance of the class with the input data
  3366. *
  3367. * @access public
  3368. * @param string $data Input data
  3369. */
  3370. public function __construct($data)
  3371. {
  3372. $this->data = $data;
  3373. }
  3374. /**
  3375. * Parse the input data
  3376. *
  3377. * @access public
  3378. * @return string Output data
  3379. */
  3380. public function parse()
  3381. {
  3382. while (($this->position = strpos($this->data, '&', $this->position)) !== false)
  3383. {
  3384. $this->consume();
  3385. $this->entity();
  3386. $this->consumed = '';
  3387. }
  3388. return $this->data;
  3389. }
  3390. /**
  3391. * Consume the next byte
  3392. *
  3393. * @access private
  3394. * @return mixed The next byte, or false, if there is no more data
  3395. */
  3396. public function consume()
  3397. {
  3398. if (isset($this->data[$this->position]))
  3399. {
  3400. $this->consumed .= $this->data[$this->position];
  3401. return $this->data[$this->position++];
  3402. }
  3403. else
  3404. {
  3405. return false;
  3406. }
  3407. }
  3408. /**
  3409. * Consume a range of characters
  3410. *
  3411. * @access private
  3412. * @param string $chars Characters to consume
  3413. * @return mixed A series of characters that match the range, or false
  3414. */
  3415. public function consume_range($chars)
  3416. {
  3417. if ($len = strspn($this->data, $chars, $this->position))
  3418. {
  3419. $data = substr($this->data, $this->position, $len);
  3420. $this->consumed .= $data;
  3421. $this->position += $len;
  3422. return $data;
  3423. }
  3424. else
  3425. {
  3426. return false;
  3427. }
  3428. }
  3429. /**
  3430. * Unconsume one byte
  3431. *
  3432. * @access private
  3433. */
  3434. public function unconsume()
  3435. {
  3436. $this->consumed = substr($this->consumed, 0, -1);
  3437. $this->position--;
  3438. }
  3439. /**
  3440. * Decode an entity
  3441. *
  3442. * @access private
  3443. */
  3444. public function entity()
  3445. {
  3446. switch ($this->consume())
  3447. {
  3448. case "\x09":
  3449. case "\x0A":
  3450. case "\x0B":
  3451. case "\x0B":
  3452. case "\x0C":
  3453. case "\x20":
  3454. case "\x3C":
  3455. case "\x26":
  3456. case false:
  3457. break;
  3458. case "\x23":
  3459. switch ($this->consume())
  3460. {
  3461. case "\x78":
  3462. case "\x58":
  3463. $range = '0123456789ABCDEFabcdef';
  3464. $hex = true;
  3465. break;
  3466. default:
  3467. $range = '0123456789';
  3468. $hex = false;
  3469. $this->unconsume();
  3470. break;
  3471. }
  3472. if ($codepoint = $this->consume_range($range))
  3473. {
  3474. static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
  3475. if ($hex)
  3476. {
  3477. $codepoint = hexdec($codepoint);
  3478. }
  3479. else
  3480. {
  3481. $codepoint = intval($codepoint);
  3482. }
  3483. if (isset($windows_1252_specials[$codepoint]))
  3484. {
  3485. $replacement = $windows_1252_specials[$codepoint];
  3486. }
  3487. else
  3488. {
  3489. $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
  3490. }
  3491. if (!in_array($this->consume(), array(';', false), true))
  3492. {
  3493. $this->unconsume();
  3494. }
  3495. $consumed_length = strlen($this->consumed);
  3496. $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
  3497. $this->position += strlen($replacement) - $consumed_length;
  3498. }
  3499. break;
  3500. default:
  3501. static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C");
  3502. for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
  3503. {
  3504. $consumed = substr($this->consumed, 1);
  3505. if (isset($entities[$consumed]))
  3506. {
  3507. $match = $consumed;
  3508. }
  3509. }
  3510. if ($match !== null)
  3511. {
  3512. $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
  3513. $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
  3514. }
  3515. break;
  3516. }
  3517. }
  3518. }
  3519. /**
  3520. * IRI parser/serialiser
  3521. *
  3522. * @package SimplePie
  3523. */
  3524. class SimplePie_IRI
  3525. {
  3526. /**
  3527. * Scheme
  3528. *
  3529. * @access private
  3530. * @var string
  3531. */
  3532. var $scheme;
  3533. /**
  3534. * User Information
  3535. *
  3536. * @access private
  3537. * @var string
  3538. */
  3539. var $userinfo;
  3540. /**
  3541. * Host
  3542. *
  3543. * @access private
  3544. * @var string
  3545. */
  3546. var $host;
  3547. /**
  3548. * Port
  3549. *
  3550. * @access private
  3551. * @var string
  3552. */
  3553. var $port;
  3554. /**
  3555. * Path
  3556. *
  3557. * @access private
  3558. * @var string
  3559. */
  3560. var $path;
  3561. /**
  3562. * Query
  3563. *
  3564. * @access private
  3565. * @var string
  3566. */
  3567. var $query;
  3568. /**
  3569. * Fragment
  3570. *
  3571. * @access private
  3572. * @var string
  3573. */
  3574. var $fragment;
  3575. /**
  3576. * Whether the object represents a valid IRI
  3577. *
  3578. * @access private
  3579. * @var array
  3580. */
  3581. var $valid = array();
  3582. /**
  3583. * Return the entire IRI when you try and read the object as a string
  3584. *
  3585. * @access public
  3586. * @return string
  3587. */
  3588. public function __toString()
  3589. {
  3590. return $this->get_iri();
  3591. }
  3592. /**
  3593. * Create a new IRI object, from a specified string
  3594. *
  3595. * @access public
  3596. * @param string $iri
  3597. * @return SimplePie_IRI
  3598. */
  3599. public function __construct($iri)
  3600. {
  3601. $iri = (string) $iri;
  3602. if ($iri !== '')
  3603. {
  3604. $parsed = $this->parse_iri($iri);
  3605. $this->set_scheme($parsed['scheme']);
  3606. $this->set_authority($parsed['authority']);
  3607. $this->set_path($parsed['path']);
  3608. $this->set_query($parsed['query']);
  3609. $this->set_fragment($parsed['fragment']);
  3610. }
  3611. }
  3612. /**
  3613. * Create a new IRI object by resolving a relative IRI
  3614. *
  3615. * @param SimplePie_IRI $base Base IRI
  3616. * @param string $relative Relative IRI
  3617. * @return SimplePie_IRI
  3618. */
  3619. public static function absolutize($base, $relative)
  3620. {
  3621. $relative = (string) $relative;
  3622. if ($relative !== '')
  3623. {
  3624. $relative = new SimplePie_IRI($relative);
  3625. if ($relative->get_scheme() !== null)
  3626. {
  3627. $target = $relative;
  3628. }
  3629. elseif ($base->get_iri() !== null)
  3630. {
  3631. if ($relative->get_authority() !== null)
  3632. {
  3633. $target = $relative;
  3634. $target->set_scheme($base->get_scheme());
  3635. }
  3636. else
  3637. {
  3638. $target = new SimplePie_IRI('');
  3639. $target->set_scheme($base->get_scheme());
  3640. $target->set_userinfo($base->get_userinfo());
  3641. $target->set_host($base->get_host());
  3642. $target->set_port($base->get_port());
  3643. if ($relative->get_path() !== null)
  3644. {
  3645. if (strpos($relative->get_path(), '/') === 0)
  3646. {
  3647. $target->set_path($relative->get_path());
  3648. }
  3649. elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null)
  3650. {
  3651. $target->set_path('/' . $relative->get_path());
  3652. }
  3653. elseif (($last_segment = strrpos($base->get_path(), '/')) !== false)
  3654. {
  3655. $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path());
  3656. }
  3657. else
  3658. {
  3659. $target->set_path($relative->get_path());
  3660. }
  3661. $target->set_query($relative->get_query());
  3662. }
  3663. else
  3664. {
  3665. $target->set_path($base->get_path());
  3666. if ($relative->get_query() !== null)
  3667. {
  3668. $target->set_query($relative->get_query());
  3669. }
  3670. elseif ($base->get_query() !== null)
  3671. {
  3672. $target->set_query($base->get_query());
  3673. }
  3674. }
  3675. }
  3676. $target->set_fragment($relative->get_fragment());
  3677. }
  3678. else
  3679. {
  3680. // No base URL, just return the relative URL
  3681. $target = $relative;
  3682. }
  3683. }
  3684. else
  3685. {
  3686. $target = $base;
  3687. }
  3688. return $target;
  3689. }
  3690. /**
  3691. * Parse an IRI into scheme/authority/path/query/fragment segments
  3692. *
  3693. * @access private
  3694. * @param string $iri
  3695. * @return array
  3696. */
  3697. public function parse_iri($iri)
  3698. {
  3699. preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match);
  3700. for ($i = count($match); $i <= 9; $i++)
  3701. {
  3702. $match[$i] = '';
  3703. }
  3704. return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]);
  3705. }
  3706. /**
  3707. * Remove dot segments from a path
  3708. *
  3709. * @access private
  3710. * @param string $input
  3711. * @return string
  3712. */
  3713. public function remove_dot_segments($input)
  3714. {
  3715. $output = '';
  3716. while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
  3717. {
  3718. // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
  3719. if (strpos($input, '../') === 0)
  3720. {
  3721. $input = substr($input, 3);
  3722. }
  3723. elseif (strpos($input, './') === 0)
  3724. {
  3725. $input = substr($input, 2);
  3726. }
  3727. // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
  3728. elseif (strpos($input, '/./') === 0)
  3729. {
  3730. $input = substr_replace($input, '/', 0, 3);
  3731. }
  3732. elseif ($input === '/.')
  3733. {
  3734. $input = '/';
  3735. }
  3736. // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
  3737. elseif (strpos($input, '/../') === 0)
  3738. {
  3739. $input = substr_replace($input, '/', 0, 4);
  3740. $output = substr_replace($output, '', strrpos($output, '/'));
  3741. }
  3742. elseif ($input === '/..')
  3743. {
  3744. $input = '/';
  3745. $output = substr_replace($output, '', strrpos($output, '/'));
  3746. }
  3747. // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
  3748. elseif ($input === '.' || $input === '..')
  3749. {
  3750. $input = '';
  3751. }
  3752. // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
  3753. elseif (($pos = strpos($input, '/', 1)) !== false)
  3754. {
  3755. $output .= substr($input, 0, $pos);
  3756. $input = substr_replace($input, '', 0, $pos);
  3757. }
  3758. else
  3759. {
  3760. $output .= $input;
  3761. $input = '';
  3762. }
  3763. }
  3764. return $output . $input;
  3765. }
  3766. /**
  3767. * Replace invalid character with percent encoding
  3768. *
  3769. * @access private
  3770. * @param string $string Input string
  3771. * @param string $valid_chars Valid characters
  3772. * @param int $case Normalise case
  3773. * @return string
  3774. */
  3775. public function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE)
  3776. {
  3777. // Normalise case
  3778. if ($case & SIMPLEPIE_LOWERCASE)
  3779. {
  3780. $string = strtolower($string);
  3781. }
  3782. elseif ($case & SIMPLEPIE_UPPERCASE)
  3783. {
  3784. $string = strtoupper($string);
  3785. }
  3786. // Store position and string length (to avoid constantly recalculating this)
  3787. $position = 0;
  3788. $strlen = strlen($string);
  3789. // Loop as long as we have invalid characters, advancing the position to the next invalid character
  3790. while (($position += strspn($string, $valid_chars, $position)) < $strlen)
  3791. {
  3792. // If we have a % character
  3793. if ($string[$position] === '%')
  3794. {
  3795. // If we have a pct-encoded section
  3796. if ($position + 2 < $strlen && strspn($string, '0123456789ABCDEFabcdef', $position + 1, 2) === 2)
  3797. {
  3798. // Get the the represented character
  3799. $chr = chr(hexdec(substr($string, $position + 1, 2)));
  3800. // If the character is valid, replace the pct-encoded with the actual character while normalising case
  3801. if (strpos($valid_chars, $chr) !== false)
  3802. {
  3803. if ($case & SIMPLEPIE_LOWERCASE)
  3804. {
  3805. $chr = strtolower($chr);
  3806. }
  3807. elseif ($case & SIMPLEPIE_UPPERCASE)
  3808. {
  3809. $chr = strtoupper($chr);
  3810. }
  3811. $string = substr_replace($string, $chr, $position, 3);
  3812. $strlen -= 2;
  3813. $position++;
  3814. }
  3815. // Otherwise just normalise the pct-encoded to uppercase
  3816. else
  3817. {
  3818. $string = substr_replace($string, strtoupper(substr($string, $position + 1, 2)), $position + 1, 2);
  3819. $position += 3;
  3820. }
  3821. }
  3822. // If we don't have a pct-encoded section, just replace the % with its own esccaped form
  3823. else
  3824. {
  3825. $string = substr_replace($string, '%25', $position, 1);
  3826. $strlen += 2;
  3827. $position += 3;
  3828. }
  3829. }
  3830. // If we have an invalid character, change into its pct-encoded form
  3831. else
  3832. {
  3833. $replacement = sprintf("%%%02X", ord($string[$position]));
  3834. $string = str_replace($string[$position], $replacement, $string);
  3835. $strlen = strlen($string);
  3836. }
  3837. }
  3838. return $string;
  3839. }
  3840. /**
  3841. * Check if the object represents a valid IRI
  3842. *
  3843. * @access public
  3844. * @return bool
  3845. */
  3846. public function is_valid()
  3847. {
  3848. return array_sum($this->valid) === count($this->valid);
  3849. }
  3850. /**
  3851. * Set the scheme. Returns true on success, false on failure (if there are
  3852. * any invalid characters).
  3853. *
  3854. * @access public
  3855. * @param string $scheme
  3856. * @return bool
  3857. */
  3858. public function set_scheme($scheme)
  3859. {
  3860. if ($scheme === null || $scheme === '')
  3861. {
  3862. $this->scheme = null;
  3863. }
  3864. else
  3865. {
  3866. $len = strlen($scheme);
  3867. switch (true)
  3868. {
  3869. case $len > 1:
  3870. if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1))
  3871. {
  3872. $this->scheme = null;
  3873. $this->valid[__FUNCTION__] = false;
  3874. return false;
  3875. }
  3876. case $len > 0:
  3877. if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1))
  3878. {
  3879. $this->scheme = null;
  3880. $this->valid[__FUNCTION__] = false;
  3881. return false;
  3882. }
  3883. }
  3884. $this->scheme = strtolower($scheme);
  3885. }
  3886. $this->valid[__FUNCTION__] = true;
  3887. return true;
  3888. }
  3889. /**
  3890. * Set the authority. Returns true on success, false on failure (if there are
  3891. * any invalid characters).
  3892. *
  3893. * @access public
  3894. * @param string $authority
  3895. * @return bool
  3896. */
  3897. public function set_authority($authority)
  3898. {
  3899. if (($userinfo_end = strrpos($authority, '@')) !== false)
  3900. {
  3901. $userinfo = substr($authority, 0, $userinfo_end);
  3902. $authority = substr($authority, $userinfo_end + 1);
  3903. }
  3904. else
  3905. {
  3906. $userinfo = null;
  3907. }
  3908. if (($port_start = strpos($authority, ':')) !== false)
  3909. {
  3910. $port = substr($authority, $port_start + 1);
  3911. $authority = substr($authority, 0, $port_start);
  3912. }
  3913. else
  3914. {
  3915. $port = null;
  3916. }
  3917. return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port);
  3918. }
  3919. /**
  3920. * Set the userinfo.
  3921. *
  3922. * @access public
  3923. * @param string $userinfo
  3924. * @return bool
  3925. */
  3926. public function set_userinfo($userinfo)
  3927. {
  3928. if ($userinfo === null || $userinfo === '')
  3929. {
  3930. $this->userinfo = null;
  3931. }
  3932. else
  3933. {
  3934. $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:');
  3935. }
  3936. $this->valid[__FUNCTION__] = true;
  3937. return true;
  3938. }
  3939. /**
  3940. * Set the host. Returns true on success, false on failure (if there are
  3941. * any invalid characters).
  3942. *
  3943. * @access public
  3944. * @param string $host
  3945. * @return bool
  3946. */
  3947. public function set_host($host)
  3948. {
  3949. if ($host === null || $host === '')
  3950. {
  3951. $this->host = null;
  3952. $this->valid[__FUNCTION__] = true;
  3953. return true;
  3954. }
  3955. elseif ($host[0] === '[' && substr($host, -1) === ']')
  3956. {
  3957. if (Net_IPv6::checkIPv6(substr($host, 1, -1)))
  3958. {
  3959. $this->host = $host;
  3960. $this->valid[__FUNCTION__] = true;
  3961. return true;
  3962. }
  3963. else
  3964. {
  3965. $this->host = null;
  3966. $this->valid[__FUNCTION__] = false;
  3967. return false;
  3968. }
  3969. }
  3970. else
  3971. {
  3972. $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE);
  3973. $this->valid[__FUNCTION__] = true;
  3974. return true;
  3975. }
  3976. }
  3977. /**
  3978. * Set the port. Returns true on success, false on failure (if there are
  3979. * any invalid characters).
  3980. *
  3981. * @access public
  3982. * @param string $port
  3983. * @return bool
  3984. */
  3985. public function set_port($port)
  3986. {
  3987. if ($port === null || $port === '')
  3988. {
  3989. $this->port = null;
  3990. $this->valid[__FUNCTION__] = true;
  3991. return true;
  3992. }
  3993. elseif (strspn($port, '0123456789') === strlen($port))
  3994. {
  3995. $this->port = (int) $port;
  3996. $this->valid[__FUNCTION__] = true;
  3997. return true;
  3998. }
  3999. else
  4000. {
  4001. $this->port = null;
  4002. $this->valid[__FUNCTION__] = false;
  4003. return false;
  4004. }
  4005. }
  4006. /**
  4007. * Set the path.
  4008. *
  4009. * @access public
  4010. * @param string $path
  4011. * @return bool
  4012. */
  4013. public function set_path($path)
  4014. {
  4015. if ($path === null || $path === '')
  4016. {
  4017. $this->path = null;
  4018. $this->valid[__FUNCTION__] = true;
  4019. return true;
  4020. }
  4021. elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null)
  4022. {
  4023. $this->path = null;
  4024. $this->valid[__FUNCTION__] = false;
  4025. return false;
  4026. }
  4027. else
  4028. {
  4029. $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/');
  4030. if ($this->scheme !== null)
  4031. {
  4032. $this->path = $this->remove_dot_segments($this->path);
  4033. }
  4034. $this->valid[__FUNCTION__] = true;
  4035. return true;
  4036. }
  4037. }
  4038. /**
  4039. * Set the query.
  4040. *
  4041. * @access public
  4042. * @param string $query
  4043. * @return bool
  4044. */
  4045. public function set_query($query)
  4046. {
  4047. if ($query === null || $query === '')
  4048. {
  4049. $this->query = null;
  4050. }
  4051. else
  4052. {
  4053. $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?');
  4054. }
  4055. $this->valid[__FUNCTION__] = true;
  4056. return true;
  4057. }
  4058. /**
  4059. * Set the fragment.
  4060. *
  4061. * @access public
  4062. * @param string $fragment
  4063. * @return bool
  4064. */
  4065. public function set_fragment($fragment)
  4066. {
  4067. if ($fragment === null || $fragment === '')
  4068. {
  4069. $this->fragment = null;
  4070. }
  4071. else
  4072. {
  4073. $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?');
  4074. }
  4075. $this->valid[__FUNCTION__] = true;
  4076. return true;
  4077. }
  4078. /**
  4079. * Get the complete IRI
  4080. *
  4081. * @access public
  4082. * @return string
  4083. */
  4084. public function get_iri()
  4085. {
  4086. $iri = '';
  4087. if ($this->scheme !== null)
  4088. {
  4089. $iri .= $this->scheme . ':';
  4090. }
  4091. if (($authority = $this->get_authority()) !== null)
  4092. {
  4093. $iri .= '//' . $authority;
  4094. }
  4095. if ($this->path !== null)
  4096. {
  4097. $iri .= $this->path;
  4098. }
  4099. if ($this->query !== null)
  4100. {
  4101. $iri .= '?' . $this->query;
  4102. }
  4103. if ($this->fragment !== null)
  4104. {
  4105. $iri .= '#' . $this->fragment;
  4106. }
  4107. if ($iri !== '')
  4108. {
  4109. return $iri;
  4110. }
  4111. else
  4112. {
  4113. return null;
  4114. }
  4115. }
  4116. /**
  4117. * Get the scheme
  4118. *
  4119. * @access public
  4120. * @return string
  4121. */
  4122. public function get_scheme()
  4123. {
  4124. return $this->scheme;
  4125. }
  4126. /**
  4127. * Get the complete authority
  4128. *
  4129. * @access public
  4130. * @return string
  4131. */
  4132. public function get_authority()
  4133. {
  4134. $authority = '';
  4135. if ($this->userinfo !== null)
  4136. {
  4137. $authority .= $this->userinfo . '@';
  4138. }
  4139. if ($this->host !== null)
  4140. {
  4141. $authority .= $this->host;
  4142. }
  4143. if ($this->port !== null)
  4144. {
  4145. $authority .= ':' . $this->port;
  4146. }
  4147. if ($authority !== '')
  4148. {
  4149. return $authority;
  4150. }
  4151. else
  4152. {
  4153. return null;
  4154. }
  4155. }
  4156. /**
  4157. * Get the user information
  4158. *
  4159. * @access public
  4160. * @return string
  4161. */
  4162. public function get_userinfo()
  4163. {
  4164. return $this->userinfo;
  4165. }
  4166. /**
  4167. * Get the host
  4168. *
  4169. * @access public
  4170. * @return string
  4171. */
  4172. public function get_host()
  4173. {
  4174. return $this->host;
  4175. }
  4176. /**
  4177. * Get the port
  4178. *
  4179. * @access public
  4180. * @return string
  4181. */
  4182. public function get_port()
  4183. {
  4184. return $this->port;
  4185. }
  4186. /**
  4187. * Get the path
  4188. *
  4189. * @access public
  4190. * @return string
  4191. */
  4192. public function get_path()
  4193. {
  4194. return $this->path;
  4195. }
  4196. /**
  4197. * Get the query
  4198. *
  4199. * @access public
  4200. * @return string
  4201. */
  4202. public function get_query()
  4203. {
  4204. return $this->query;
  4205. }
  4206. /**
  4207. * Get the fragment
  4208. *
  4209. * @access public
  4210. * @return string
  4211. */
  4212. public function get_fragment()
  4213. {
  4214. return $this->fragment;
  4215. }
  4216. }
  4217. /**
  4218. * Class to validate and to work with IPv6 addresses.
  4219. *
  4220. * @package SimplePie
  4221. * @copyright 2003-2005 The PHP Group
  4222. * @license http://www.opensource.org/licenses/bsd-license.php
  4223. * @link http://pear.php.net/package/Net_IPv6
  4224. * @author Alexander Merz <alexander.merz@web.de>
  4225. * @author elfrink at introweb dot nl
  4226. * @author Josh Peck <jmp at joshpeck dot org>
  4227. * @author Geoffrey Sneddon <geoffers@gmail.com>
  4228. */
  4229. class SimplePie_Net_IPv6
  4230. {
  4231. /**
  4232. * Removes a possible existing netmask specification of an IP address.
  4233. *
  4234. * @param string $ip the (compressed) IP as Hex representation
  4235. * @return string the IP the without netmask
  4236. * @since 1.1.0
  4237. */
  4238. public static function removeNetmaskSpec($ip)
  4239. {
  4240. if (strpos($ip, '/') !== false)
  4241. {
  4242. list($addr, $nm) = explode('/', $ip);
  4243. }
  4244. else
  4245. {
  4246. $addr = $ip;
  4247. }
  4248. return $addr;
  4249. }
  4250. /**
  4251. * Uncompresses an IPv6 address
  4252. *
  4253. * RFC 2373 allows you to compress zeros in an address to '::'. This
  4254. * function expects an valid IPv6 address and expands the '::' to
  4255. * the required zeros.
  4256. *
  4257. * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
  4258. * ::1 -> 0:0:0:0:0:0:0:1
  4259. *
  4260. * @access public
  4261. * @static
  4262. * @param string $ip a valid IPv6-address (hex format)
  4263. * @return string the uncompressed IPv6-address (hex format)
  4264. */
  4265. public static function Uncompress($ip)
  4266. {
  4267. $uip = SimplePie_Net_IPv6::removeNetmaskSpec($ip);
  4268. $c1 = -1;
  4269. $c2 = -1;
  4270. if (strpos($ip, '::') !== false)
  4271. {
  4272. list($ip1, $ip2) = explode('::', $ip);
  4273. if ($ip1 === '')
  4274. {
  4275. $c1 = -1;
  4276. }
  4277. else
  4278. {
  4279. $pos = 0;
  4280. if (($pos = substr_count($ip1, ':')) > 0)
  4281. {
  4282. $c1 = $pos;
  4283. }
  4284. else
  4285. {
  4286. $c1 = 0;
  4287. }
  4288. }
  4289. if ($ip2 === '')
  4290. {
  4291. $c2 = -1;
  4292. }
  4293. else
  4294. {
  4295. $pos = 0;
  4296. if (($pos = substr_count($ip2, ':')) > 0)
  4297. {
  4298. $c2 = $pos;
  4299. }
  4300. else
  4301. {
  4302. $c2 = 0;
  4303. }
  4304. }
  4305. if (strstr($ip2, '.'))
  4306. {
  4307. $c2++;
  4308. }
  4309. // ::
  4310. if ($c1 === -1 && $c2 === -1)
  4311. {
  4312. $uip = '0:0:0:0:0:0:0:0';
  4313. }
  4314. // ::xxx
  4315. else if ($c1 === -1)
  4316. {
  4317. $fill = str_repeat('0:', 7 - $c2);
  4318. $uip = str_replace('::', $fill, $uip);
  4319. }
  4320. // xxx::
  4321. else if ($c2 === -1)
  4322. {
  4323. $fill = str_repeat(':0', 7 - $c1);
  4324. $uip = str_replace('::', $fill, $uip);
  4325. }
  4326. // xxx::xxx
  4327. else
  4328. {
  4329. $fill = str_repeat(':0:', 6 - $c2 - $c1);
  4330. $uip = str_replace('::', $fill, $uip);
  4331. $uip = str_replace('::', ':', $uip);
  4332. }
  4333. }
  4334. return $uip;
  4335. }
  4336. /**
  4337. * Splits an IPv6 address into the IPv6 and a possible IPv4 part
  4338. *
  4339. * RFC 2373 allows you to note the last two parts of an IPv6 address as
  4340. * an IPv4 compatible address
  4341. *
  4342. * Example: 0:0:0:0:0:0:13.1.68.3
  4343. * 0:0:0:0:0:FFFF:129.144.52.38
  4344. *
  4345. * @access public
  4346. * @static
  4347. * @param string $ip a valid IPv6-address (hex format)
  4348. * @return array [0] contains the IPv6 part, [1] the IPv4 part (hex format)
  4349. */
  4350. public static function SplitV64($ip)
  4351. {
  4352. $ip = SimplePie_Net_IPv6::Uncompress($ip);
  4353. if (strstr($ip, '.'))
  4354. {
  4355. $pos = strrpos($ip, ':');
  4356. $ip[$pos] = '_';
  4357. $ipPart = explode('_', $ip);
  4358. return $ipPart;
  4359. }
  4360. else
  4361. {
  4362. return array($ip, '');
  4363. }
  4364. }
  4365. /**
  4366. * Checks an IPv6 address
  4367. *
  4368. * Checks if the given IP is IPv6-compatible
  4369. *
  4370. * @access public
  4371. * @static
  4372. * @param string $ip a valid IPv6-address
  4373. * @return bool true if $ip is an IPv6 address
  4374. */
  4375. public static function checkIPv6($ip)
  4376. {
  4377. $ipPart = SimplePie_Net_IPv6::SplitV64($ip);
  4378. $count = 0;
  4379. if (!empty($ipPart[0]))
  4380. {
  4381. $ipv6 = explode(':', $ipPart[0]);
  4382. for ($i = 0; $i < count($ipv6); $i++)
  4383. {
  4384. $dec = hexdec($ipv6[$i]);
  4385. $hex = strtoupper(preg_replace('/^[0]{1,3}(.*[0-9a-fA-F])$/', '\\1', $ipv6[$i]));
  4386. if ($ipv6[$i] >= 0 && $dec <= 65535 && $hex === strtoupper(dechex($dec)))
  4387. {
  4388. $count++;
  4389. }
  4390. }
  4391. if ($count === 8)
  4392. {
  4393. return true;
  4394. }
  4395. elseif ($count === 6 && !empty($ipPart[1]))
  4396. {
  4397. $ipv4 = explode('.', $ipPart[1]);
  4398. $count = 0;
  4399. foreach ($ipv4 as $ipv4_part)
  4400. {
  4401. if ($ipv4_part >= 0 && $ipv4_part <= 255 && preg_match('/^\d{1,3}$/', $ipv4_part))
  4402. {
  4403. $count++;
  4404. }
  4405. }
  4406. if ($count === 4)
  4407. {
  4408. return true;
  4409. }
  4410. }
  4411. else
  4412. {
  4413. return false;
  4414. }
  4415. }
  4416. else
  4417. {
  4418. return false;
  4419. }
  4420. }
  4421. }
  4422. /**
  4423. * Date Parser
  4424. *
  4425. * @package SimplePie
  4426. */
  4427. class SimplePie_Parse_Date
  4428. {
  4429. /**
  4430. * Input data
  4431. *
  4432. * @access protected
  4433. * @var string
  4434. */
  4435. var $date;
  4436. /**
  4437. * List of days, calendar day name => ordinal day number in the week
  4438. *
  4439. * @access protected
  4440. * @var array
  4441. */
  4442. var $day = array(
  4443. 'mon' => 1,
  4444. 'monday' => 1,
  4445. 'tue' => 2,
  4446. 'tuesday' => 2,
  4447. 'wed' => 3,
  4448. 'wednesday' => 3,
  4449. 'thu' => 4,
  4450. 'thursday' => 4,
  4451. 'fri' => 5,
  4452. 'friday' => 5,
  4453. 'sat' => 6,
  4454. 'saturday' => 6,
  4455. 'sun' => 7,
  4456. 'sunday' => 7,
  4457. );
  4458. /**
  4459. * List of months, calendar month name => calendar month number
  4460. *
  4461. * @access protected
  4462. * @var array
  4463. */
  4464. var $month = array(
  4465. 'jan' => 1,
  4466. 'january' => 1,
  4467. 'feb' => 2,
  4468. 'february' => 2,
  4469. 'mar' => 3,
  4470. 'march' => 3,
  4471. 'apr' => 4,
  4472. 'april' => 4,
  4473. 'may' => 5,
  4474. // No long form of May
  4475. 'jun' => 6,
  4476. 'june' => 6,
  4477. 'jul' => 7,
  4478. 'july' => 7,
  4479. 'aug' => 8,
  4480. 'august' => 8,
  4481. 'sep' => 9,
  4482. 'september' => 8,
  4483. 'oct' => 10,
  4484. 'october' => 10,
  4485. 'nov' => 11,
  4486. 'november' => 11,
  4487. 'dec' => 12,
  4488. 'december' => 12,
  4489. );
  4490. /**
  4491. * List of timezones, abbreviation => offset from UTC
  4492. *
  4493. * @access protected
  4494. * @var array
  4495. */
  4496. var $timezone = array(
  4497. 'CDT' => -18000,
  4498. 'CST' => -21600,
  4499. 'EDT' => -14400,
  4500. 'EST' => -18000,
  4501. 'MDT' => -21600,
  4502. 'MST' => -25200,
  4503. 'PDT' => -25200,
  4504. 'PST' => -28800,
  4505. );
  4506. /**
  4507. * Cached PCRE for SimplePie_Parse_Date::$day
  4508. *
  4509. * @access protected
  4510. * @var string
  4511. */
  4512. var $day_pcre;
  4513. /**
  4514. * Cached PCRE for SimplePie_Parse_Date::$month
  4515. *
  4516. * @access protected
  4517. * @var string
  4518. */
  4519. var $month_pcre;
  4520. /**
  4521. * Array of user-added callback methods
  4522. *
  4523. * @access private
  4524. * @var array
  4525. */
  4526. var $built_in = array();
  4527. /**
  4528. * Array of user-added callback methods
  4529. *
  4530. * @access private
  4531. * @var array
  4532. */
  4533. var $user = array();
  4534. /**
  4535. * Create new SimplePie_Parse_Date object, and set self::day_pcre,
  4536. * self::month_pcre, and self::built_in
  4537. *
  4538. * @access private
  4539. */
  4540. public function __construct()
  4541. {
  4542. $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
  4543. $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
  4544. static $cache;
  4545. if (!isset($cache[get_class($this)]))
  4546. {
  4547. $all_methods = get_class_methods($this);
  4548. foreach ($all_methods as $method)
  4549. {
  4550. if (strtolower(substr($method, 0, 5)) === 'date_')
  4551. {
  4552. $cache[get_class($this)][] = $method;
  4553. }
  4554. }
  4555. }
  4556. foreach ($cache[get_class($this)] as $method)
  4557. {
  4558. $this->built_in[] = $method;
  4559. }
  4560. }
  4561. /**
  4562. * Get the object
  4563. *
  4564. * @access public
  4565. */
  4566. public static function get()
  4567. {
  4568. static $object;
  4569. if (!$object)
  4570. {
  4571. $object = new SimplePie_Parse_Date;
  4572. }
  4573. return $object;
  4574. }
  4575. /**
  4576. * Parse a date
  4577. *
  4578. * @final
  4579. * @access public
  4580. * @param string $date Date to parse
  4581. * @return int Timestamp corresponding to date string, or false on failure
  4582. */
  4583. public function parse($date)
  4584. {
  4585. foreach ($this->user as $method)
  4586. {
  4587. if (($returned = call_user_func($method, $date)) !== false)
  4588. {
  4589. return $returned;
  4590. }
  4591. }
  4592. foreach ($this->built_in as $method)
  4593. {
  4594. if (($returned = call_user_func(array(&$this, $method), $date)) !== false)
  4595. {
  4596. return $returned;
  4597. }
  4598. }
  4599. return false;
  4600. }
  4601. /**
  4602. * Add a callback method to parse a date
  4603. *
  4604. * @final
  4605. * @access public
  4606. * @param callback $callback
  4607. */
  4608. public function add_callback($callback)
  4609. {
  4610. if (is_callable($callback))
  4611. {
  4612. $this->user[] = $callback;
  4613. }
  4614. else
  4615. {
  4616. trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
  4617. }
  4618. }
  4619. /**
  4620. * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
  4621. * well as allowing any of upper or lower case "T", horizontal tabs, or
  4622. * spaces to be used as the time seperator (including more than one))
  4623. *
  4624. * @access protected
  4625. * @return int Timestamp
  4626. */
  4627. public function date_w3cdtf($date)
  4628. {
  4629. static $pcre;
  4630. if (!$pcre)
  4631. {
  4632. $year = '([0-9]{4})';
  4633. $month = $day = $hour = $minute = $second = '([0-9]{2})';
  4634. $decimal = '([0-9]*)';
  4635. $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
  4636. $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
  4637. }
  4638. if (preg_match($pcre, $date, $match))
  4639. {
  4640. /*
  4641. Capturing subpatterns:
  4642. 1: Year
  4643. 2: Month
  4644. 3: Day
  4645. 4: Hour
  4646. 5: Minute
  4647. 6: Second
  4648. 7: Decimal fraction of a second
  4649. 8: Zulu
  4650. 9: Timezone ±
  4651. 10: Timezone hours
  4652. 11: Timezone minutes
  4653. */
  4654. // Fill in empty matches
  4655. for ($i = count($match); $i <= 3; $i++)
  4656. {
  4657. $match[$i] = '1';
  4658. }
  4659. for ($i = count($match); $i <= 7; $i++)
  4660. {
  4661. $match[$i] = '0';
  4662. }
  4663. // Numeric timezone
  4664. if (isset($match[9]) && $match[9] !== '')
  4665. {
  4666. $timezone = $match[10] * 3600;
  4667. $timezone += $match[11] * 60;
  4668. if ($match[9] === '-')
  4669. {
  4670. $timezone = 0 - $timezone;
  4671. }
  4672. }
  4673. else
  4674. {
  4675. $timezone = 0;
  4676. }
  4677. // Convert the number of seconds to an integer, taking decimals into account
  4678. $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
  4679. return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
  4680. }
  4681. else
  4682. {
  4683. return false;
  4684. }
  4685. }
  4686. /**
  4687. * Remove RFC822 comments
  4688. *
  4689. * @access protected
  4690. * @param string $data Data to strip comments from
  4691. * @return string Comment stripped string
  4692. */
  4693. public function remove_rfc2822_comments($string)
  4694. {
  4695. $string = (string) $string;
  4696. $position = 0;
  4697. $length = strlen($string);
  4698. $depth = 0;
  4699. $output = '';
  4700. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  4701. {
  4702. $output .= substr($string, $position, $pos - $position);
  4703. $position = $pos + 1;
  4704. if ($string[$pos - 1] !== '\\')
  4705. {
  4706. $depth++;
  4707. while ($depth && $position < $length)
  4708. {
  4709. $position += strcspn($string, '()', $position);
  4710. if ($string[$position - 1] === '\\')
  4711. {
  4712. $position++;
  4713. continue;
  4714. }
  4715. elseif (isset($string[$position]))
  4716. {
  4717. switch ($string[$position])
  4718. {
  4719. case '(':
  4720. $depth++;
  4721. break;
  4722. case ')':
  4723. $depth--;
  4724. break;
  4725. }
  4726. $position++;
  4727. }
  4728. else
  4729. {
  4730. break;
  4731. }
  4732. }
  4733. }
  4734. else
  4735. {
  4736. $output .= '(';
  4737. }
  4738. }
  4739. $output .= substr($string, $position);
  4740. return $output;
  4741. }
  4742. /**
  4743. * Parse RFC2822's date format
  4744. *
  4745. * @access protected
  4746. * @return int Timestamp
  4747. */
  4748. public function date_rfc2822($date)
  4749. {
  4750. static $pcre;
  4751. if (!$pcre)
  4752. {
  4753. $wsp = '[\x09\x20]';
  4754. $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
  4755. $optional_fws = $fws . '?';
  4756. $day_name = $this->day_pcre;
  4757. $month = $this->month_pcre;
  4758. $day = '([0-9]{1,2})';
  4759. $hour = $minute = $second = '([0-9]{2})';
  4760. $year = '([0-9]{2,4})';
  4761. $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
  4762. $character_zone = '([A-Z]{1,5})';
  4763. $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
  4764. $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
  4765. }
  4766. if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
  4767. {
  4768. /*
  4769. Capturing subpatterns:
  4770. 1: Day name
  4771. 2: Day
  4772. 3: Month
  4773. 4: Year
  4774. 5: Hour
  4775. 6: Minute
  4776. 7: Second
  4777. 8: Timezone ±
  4778. 9: Timezone hours
  4779. 10: Timezone minutes
  4780. 11: Alphabetic timezone
  4781. */
  4782. // Find the month number
  4783. $month = $this->month[strtolower($match[3])];
  4784. // Numeric timezone
  4785. if ($match[8] !== '')
  4786. {
  4787. $timezone = $match[9] * 3600;
  4788. $timezone += $match[10] * 60;
  4789. if ($match[8] === '-')
  4790. {
  4791. $timezone = 0 - $timezone;
  4792. }
  4793. }
  4794. // Character timezone
  4795. elseif (isset($this->timezone[strtoupper($match[11])]))
  4796. {
  4797. $timezone = $this->timezone[strtoupper($match[11])];
  4798. }
  4799. // Assume everything else to be -0000
  4800. else
  4801. {
  4802. $timezone = 0;
  4803. }
  4804. // Deal with 2/3 digit years
  4805. if ($match[4] < 50)
  4806. {
  4807. $match[4] += 2000;
  4808. }
  4809. elseif ($match[4] < 1000)
  4810. {
  4811. $match[4] += 1900;
  4812. }
  4813. // Second is optional, if it is empty set it to zero
  4814. if ($match[7] !== '')
  4815. {
  4816. $second = $match[7];
  4817. }
  4818. else
  4819. {
  4820. $second = 0;
  4821. }
  4822. return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
  4823. }
  4824. else
  4825. {
  4826. return false;
  4827. }
  4828. }
  4829. /**
  4830. * Parse RFC850's date format
  4831. *
  4832. * @access protected
  4833. * @return int Timestamp
  4834. */
  4835. public function date_rfc850($date)
  4836. {
  4837. static $pcre;
  4838. if (!$pcre)
  4839. {
  4840. $space = '[\x09\x20]+';
  4841. $day_name = $this->day_pcre;
  4842. $month = $this->month_pcre;
  4843. $day = '([0-9]{1,2})';
  4844. $year = $hour = $minute = $second = '([0-9]{2})';
  4845. $zone = '([A-Z]{1,5})';
  4846. $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
  4847. }
  4848. if (preg_match($pcre, $date, $match))
  4849. {
  4850. /*
  4851. Capturing subpatterns:
  4852. 1: Day name
  4853. 2: Day
  4854. 3: Month
  4855. 4: Year
  4856. 5: Hour
  4857. 6: Minute
  4858. 7: Second
  4859. 8: Timezone
  4860. */
  4861. // Month
  4862. $month = $this->month[strtolower($match[3])];
  4863. // Character timezone
  4864. if (isset($this->timezone[strtoupper($match[8])]))
  4865. {
  4866. $timezone = $this->timezone[strtoupper($match[8])];
  4867. }
  4868. // Assume everything else to be -0000
  4869. else
  4870. {
  4871. $timezone = 0;
  4872. }
  4873. // Deal with 2 digit year
  4874. if ($match[4] < 50)
  4875. {
  4876. $match[4] += 2000;
  4877. }
  4878. else
  4879. {
  4880. $match[4] += 1900;
  4881. }
  4882. return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
  4883. }
  4884. else
  4885. {
  4886. return false;
  4887. }
  4888. }
  4889. /**
  4890. * Parse C99's asctime()'s date format
  4891. *
  4892. * @access protected
  4893. * @return int Timestamp
  4894. */
  4895. public function date_asctime($date)
  4896. {
  4897. static $pcre;
  4898. if (!$pcre)
  4899. {
  4900. $space = '[\x09\x20]+';
  4901. $wday_name = $this->day_pcre;
  4902. $mon_name = $this->month_pcre;
  4903. $day = '([0-9]{1,2})';
  4904. $hour = $sec = $min = '([0-9]{2})';
  4905. $year = '([0-9]{4})';
  4906. $terminator = '\x0A?\x00?';
  4907. $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
  4908. }
  4909. if (preg_match($pcre, $date, $match))
  4910. {
  4911. /*
  4912. Capturing subpatterns:
  4913. 1: Day name
  4914. 2: Month
  4915. 3: Day
  4916. 4: Hour
  4917. 5: Minute
  4918. 6: Second
  4919. 7: Year
  4920. */
  4921. $month = $this->month[strtolower($match[2])];
  4922. return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
  4923. }
  4924. else
  4925. {
  4926. return false;
  4927. }
  4928. }
  4929. /**
  4930. * Parse dates using strtotime()
  4931. *
  4932. * @access protected
  4933. * @return int Timestamp
  4934. */
  4935. public function date_strtotime($date)
  4936. {
  4937. $strtotime = strtotime($date);
  4938. if ($strtotime === -1 || $strtotime === false)
  4939. {
  4940. return false;
  4941. }
  4942. else
  4943. {
  4944. return $strtotime;
  4945. }
  4946. }
  4947. }
  4948. class SimplePie_Parser
  4949. {
  4950. var $error_code;
  4951. var $error_string;
  4952. var $current_line;
  4953. var $current_column;
  4954. var $current_byte;
  4955. var $separator = ' ';
  4956. var $namespace = array('');
  4957. var $element = array('');
  4958. var $xml_base = array('');
  4959. var $xml_base_explicit = array(false);
  4960. var $xml_lang = array('');
  4961. var $data = array();
  4962. var $datas = array(array());
  4963. var $current_xhtml_construct = -1;
  4964. public function parse(&$data)
  4965. {
  4966. $return = true;
  4967. static $xml_is_sane = null;
  4968. if ($xml_is_sane === null)
  4969. {
  4970. $parser_check = xml_parser_create();
  4971. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  4972. xml_parser_free($parser_check);
  4973. $xml_is_sane = isset($values[0]['value']);
  4974. }
  4975. // Create the parser
  4976. if ($xml_is_sane)
  4977. {
  4978. $xml = xml_parser_create_ns('UTF-8', $this->separator);
  4979. xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
  4980. xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
  4981. xml_set_object($xml, $this);
  4982. xml_set_character_data_handler($xml, 'cdata');
  4983. xml_set_element_handler($xml, 'tag_open', 'tag_close');
  4984. // Parse!
  4985. if (!xml_parse($xml, $data, true))
  4986. {
  4987. $this->error_code = xml_get_error_code($xml);
  4988. $this->error_string = xml_error_string($this->error_code);
  4989. $return = false;
  4990. }
  4991. $this->current_line = xml_get_current_line_number($xml);
  4992. $this->current_column = xml_get_current_column_number($xml);
  4993. $this->current_byte = xml_get_current_byte_index($xml);
  4994. xml_parser_free($xml);
  4995. return $return;
  4996. }
  4997. else
  4998. {
  4999. libxml_clear_errors();
  5000. $xml = new XMLReader();
  5001. $xml->xml($data);
  5002. while (@$xml->read())
  5003. {
  5004. switch ($xml->nodeType)
  5005. {
  5006. case constant('XMLReader::END_ELEMENT'):
  5007. if ($xml->namespaceURI !== '')
  5008. {
  5009. $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
  5010. }
  5011. else
  5012. {
  5013. $tagName = $xml->localName;
  5014. }
  5015. $this->tag_close(null, $tagName);
  5016. break;
  5017. case constant('XMLReader::ELEMENT'):
  5018. $empty = $xml->isEmptyElement;
  5019. if ($xml->namespaceURI !== '')
  5020. {
  5021. $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
  5022. }
  5023. else
  5024. {
  5025. $tagName = $xml->localName;
  5026. }
  5027. $attributes = array();
  5028. while ($xml->moveToNextAttribute())
  5029. {
  5030. if ($xml->namespaceURI !== '')
  5031. {
  5032. $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
  5033. }
  5034. else
  5035. {
  5036. $attrName = $xml->localName;
  5037. }
  5038. $attributes[$attrName] = $xml->value;
  5039. }
  5040. $this->tag_open(null, $tagName, $attributes);
  5041. if ($empty)
  5042. {
  5043. $this->tag_close(null, $tagName);
  5044. }
  5045. break;
  5046. case constant('XMLReader::TEXT'):
  5047. case constant('XMLReader::CDATA'):
  5048. $this->cdata(null, $xml->value);
  5049. break;
  5050. }
  5051. }
  5052. if ($error = libxml_get_last_error())
  5053. {
  5054. $this->error_code = $error->code;
  5055. $this->error_string = $error->message;
  5056. $this->current_line = $error->line;
  5057. $this->current_column = $error->column;
  5058. return false;
  5059. }
  5060. else
  5061. {
  5062. return true;
  5063. }
  5064. }
  5065. }
  5066. public function get_error_code()
  5067. {
  5068. return $this->error_code;
  5069. }
  5070. public function get_error_string()
  5071. {
  5072. return $this->error_string;
  5073. }
  5074. public function get_current_line()
  5075. {
  5076. return $this->current_line;
  5077. }
  5078. public function get_current_column()
  5079. {
  5080. return $this->current_column;
  5081. }
  5082. public function get_current_byte()
  5083. {
  5084. return $this->current_byte;
  5085. }
  5086. public function get_data()
  5087. {
  5088. return $this->data;
  5089. }
  5090. public function tag_open($parser, $tag, $attributes)
  5091. {
  5092. list($this->namespace[], $this->element[]) = $this->split_ns($tag);
  5093. $attribs = array();
  5094. foreach ($attributes as $name => $value)
  5095. {
  5096. list($attrib_namespace, $attribute) = $this->split_ns($name);
  5097. $attribs[$attrib_namespace][$attribute] = $value;
  5098. }
  5099. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
  5100. {
  5101. $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base));
  5102. $this->xml_base_explicit[] = true;
  5103. }
  5104. else
  5105. {
  5106. $this->xml_base[] = end($this->xml_base);
  5107. $this->xml_base_explicit[] = end($this->xml_base_explicit);
  5108. }
  5109. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
  5110. {
  5111. $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
  5112. }
  5113. else
  5114. {
  5115. $this->xml_lang[] = end($this->xml_lang);
  5116. }
  5117. if ($this->current_xhtml_construct >= 0)
  5118. {
  5119. $this->current_xhtml_construct++;
  5120. if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
  5121. {
  5122. $this->data['data'] .= '<' . end($this->element);
  5123. if (isset($attribs['']))
  5124. {
  5125. foreach ($attribs[''] as $name => $value)
  5126. {
  5127. $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"';
  5128. }
  5129. }
  5130. $this->data['data'] .= '>';
  5131. }
  5132. }
  5133. else
  5134. {
  5135. $this->datas[] =& $this->data;
  5136. $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
  5137. $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
  5138. if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml')
  5139. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml'))
  5140. {
  5141. $this->current_xhtml_construct = 0;
  5142. }
  5143. }
  5144. }
  5145. public function cdata($parser, $cdata)
  5146. {
  5147. if ($this->current_xhtml_construct >= 0)
  5148. {
  5149. $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, 'UTF-8');
  5150. }
  5151. else
  5152. {
  5153. $this->data['data'] .= $cdata;
  5154. }
  5155. }
  5156. public function tag_close($parser, $tag)
  5157. {
  5158. if ($this->current_xhtml_construct >= 0)
  5159. {
  5160. $this->current_xhtml_construct--;
  5161. if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
  5162. {
  5163. $this->data['data'] .= '</' . end($this->element) . '>';
  5164. }
  5165. }
  5166. if ($this->current_xhtml_construct === -1)
  5167. {
  5168. $this->data =& $this->datas[count($this->datas) - 1];
  5169. array_pop($this->datas);
  5170. }
  5171. array_pop($this->element);
  5172. array_pop($this->namespace);
  5173. array_pop($this->xml_base);
  5174. array_pop($this->xml_base_explicit);
  5175. array_pop($this->xml_lang);
  5176. }
  5177. public function split_ns($string)
  5178. {
  5179. static $cache = array();
  5180. if (!isset($cache[$string]))
  5181. {
  5182. if ($pos = strpos($string, $this->separator))
  5183. {
  5184. static $separator_length;
  5185. if (!$separator_length)
  5186. {
  5187. $separator_length = strlen($this->separator);
  5188. }
  5189. $namespace = substr($string, 0, $pos);
  5190. $local_name = substr($string, $pos + $separator_length);
  5191. $cache[$string] = array($namespace, $local_name);
  5192. }
  5193. else
  5194. {
  5195. $cache[$string] = array('', $string);
  5196. }
  5197. }
  5198. return $cache[$string];
  5199. }
  5200. }
  5201. /**
  5202. * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
  5203. */
  5204. class SimplePie_Sanitize
  5205. {
  5206. // Private vars
  5207. var $base;
  5208. var $replace_url_attributes = array(
  5209. 'a' => 'href',
  5210. 'area' => 'href',
  5211. 'blockquote' => 'cite',
  5212. 'del' => 'cite',
  5213. 'form' => 'action',
  5214. 'img' => array('longdesc', 'src'),
  5215. 'input' => 'src',
  5216. 'ins' => 'cite',
  5217. 'q' => 'cite'
  5218. );
  5219. /**
  5220. * Set element/attribute key/value pairs of HTML attributes
  5221. * containing URLs that need to be resolved relative to the feed
  5222. *
  5223. * @access public
  5224. * @since 1.0
  5225. * @param array $element_attribute Element/attribute key/value pairs
  5226. */
  5227. public function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
  5228. {
  5229. $this->replace_url_attributes = (array) $element_attribute;
  5230. }
  5231. public function sanitize($data, $type, $base = '')
  5232. {
  5233. $data = trim($data);
  5234. if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
  5235. {
  5236. if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
  5237. {
  5238. $data = base64_decode($data);
  5239. }
  5240. if ($type & SIMPLEPIE_CONSTRUCT_XHTML)
  5241. {
  5242. $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
  5243. $data = preg_replace('/<\/div>$/', '', $data);
  5244. }
  5245. if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
  5246. {
  5247. // Replace relative URLs
  5248. $this->base = $base;
  5249. foreach ($this->replace_url_attributes as $element => $attributes)
  5250. {
  5251. $data = $this->replace_urls($data, $element, $attributes);
  5252. }
  5253. // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data
  5254. $data = trim($data);
  5255. }
  5256. if ($type & SIMPLEPIE_CONSTRUCT_IRI)
  5257. {
  5258. $data = SimplePie_Misc::absolutize_url($data, $base);
  5259. }
  5260. if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
  5261. {
  5262. $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
  5263. }
  5264. }
  5265. return $data;
  5266. }
  5267. public function replace_urls($data, $tag, $attributes)
  5268. {
  5269. $elements = SimplePie_Misc::get_element($tag, $data);
  5270. foreach ($elements as $element)
  5271. {
  5272. if (is_array($attributes))
  5273. {
  5274. foreach ($attributes as $attribute)
  5275. {
  5276. if (isset($element['attribs'][$attribute]['data']))
  5277. {
  5278. $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base);
  5279. $new_element = SimplePie_Misc::element_implode($element);
  5280. $data = str_replace($element['full'], $new_element, $data);
  5281. $element['full'] = $new_element;
  5282. }
  5283. }
  5284. }
  5285. elseif (isset($element['attribs'][$attributes]['data']))
  5286. {
  5287. $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base);
  5288. $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data);
  5289. }
  5290. }
  5291. return $data;
  5292. }
  5293. }