PageRenderTime 186ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 3ms

/social/extensions/yii-feed-widget/SimplePie.php

https://github.com/najeebbuzinessware/socialintranet
PHP | 17597 lines | 12998 code | 955 blank | 3644 comment | 1255 complexity | ba6df1ab95535d7258c64cf5e5a83eff MD5 | raw file
  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. * Please note: This file is automatically generated by a build script. The
  9. * full original source is always available from http://simplepie.org/
  10. *
  11. * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without modification, are
  15. * permitted provided that the following conditions are met:
  16. *
  17. * * Redistributions of source code must retain the above copyright notice, this list of
  18. * conditions and the following disclaimer.
  19. *
  20. * * Redistributions in binary form must reproduce the above copyright notice, this list
  21. * of conditions and the following disclaimer in the documentation and/or other materials
  22. * provided with the distribution.
  23. *
  24. * * Neither the name of the SimplePie Team nor the names of its contributors may be used
  25. * to endorse or promote products derived from this software without specific prior
  26. * written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  30. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  31. * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  33. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  34. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  35. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * @package SimplePie
  39. * @version 1.4-dev
  40. * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  41. * @author Ryan Parman
  42. * @author Geoffrey Sneddon
  43. * @author Ryan McCue
  44. * @link http://simplepie.org/ SimplePie
  45. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  46. */
  47. /**
  48. * SimplePie Name
  49. */
  50. define('SIMPLEPIE_NAME', 'SimplePie');
  51. /**
  52. * SimplePie Version
  53. */
  54. define('SIMPLEPIE_VERSION', '1.4-dev');
  55. /**
  56. * SimplePie Build
  57. * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
  58. */
  59. define('SIMPLEPIE_BUILD', '20120708064102');
  60. /**
  61. * SimplePie Website URL
  62. */
  63. define('SIMPLEPIE_URL', 'http://simplepie.org');
  64. /**
  65. * SimplePie Useragent
  66. * @see SimplePie::set_useragent()
  67. */
  68. define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
  69. /**
  70. * SimplePie Linkback
  71. */
  72. define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
  73. /**
  74. * No Autodiscovery
  75. * @see SimplePie::set_autodiscovery_level()
  76. */
  77. define('SIMPLEPIE_LOCATOR_NONE', 0);
  78. /**
  79. * Feed Link Element Autodiscovery
  80. * @see SimplePie::set_autodiscovery_level()
  81. */
  82. define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
  83. /**
  84. * Local Feed Extension Autodiscovery
  85. * @see SimplePie::set_autodiscovery_level()
  86. */
  87. define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
  88. /**
  89. * Local Feed Body Autodiscovery
  90. * @see SimplePie::set_autodiscovery_level()
  91. */
  92. define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
  93. /**
  94. * Remote Feed Extension Autodiscovery
  95. * @see SimplePie::set_autodiscovery_level()
  96. */
  97. define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
  98. /**
  99. * Remote Feed Body Autodiscovery
  100. * @see SimplePie::set_autodiscovery_level()
  101. */
  102. define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
  103. /**
  104. * All Feed Autodiscovery
  105. * @see SimplePie::set_autodiscovery_level()
  106. */
  107. define('SIMPLEPIE_LOCATOR_ALL', 31);
  108. /**
  109. * No known feed type
  110. */
  111. define('SIMPLEPIE_TYPE_NONE', 0);
  112. /**
  113. * RSS 0.90
  114. */
  115. define('SIMPLEPIE_TYPE_RSS_090', 1);
  116. /**
  117. * RSS 0.91 (Netscape)
  118. */
  119. define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
  120. /**
  121. * RSS 0.91 (Userland)
  122. */
  123. define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
  124. /**
  125. * RSS 0.91 (both Netscape and Userland)
  126. */
  127. define('SIMPLEPIE_TYPE_RSS_091', 6);
  128. /**
  129. * RSS 0.92
  130. */
  131. define('SIMPLEPIE_TYPE_RSS_092', 8);
  132. /**
  133. * RSS 0.93
  134. */
  135. define('SIMPLEPIE_TYPE_RSS_093', 16);
  136. /**
  137. * RSS 0.94
  138. */
  139. define('SIMPLEPIE_TYPE_RSS_094', 32);
  140. /**
  141. * RSS 1.0
  142. */
  143. define('SIMPLEPIE_TYPE_RSS_10', 64);
  144. /**
  145. * RSS 2.0
  146. */
  147. define('SIMPLEPIE_TYPE_RSS_20', 128);
  148. /**
  149. * RDF-based RSS
  150. */
  151. define('SIMPLEPIE_TYPE_RSS_RDF', 65);
  152. /**
  153. * Non-RDF-based RSS (truly intended as syndication format)
  154. */
  155. define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
  156. /**
  157. * All RSS
  158. */
  159. define('SIMPLEPIE_TYPE_RSS_ALL', 255);
  160. /**
  161. * Atom 0.3
  162. */
  163. define('SIMPLEPIE_TYPE_ATOM_03', 256);
  164. /**
  165. * Atom 1.0
  166. */
  167. define('SIMPLEPIE_TYPE_ATOM_10', 512);
  168. /**
  169. * All Atom
  170. */
  171. define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
  172. /**
  173. * All feed types
  174. */
  175. define('SIMPLEPIE_TYPE_ALL', 1023);
  176. /**
  177. * No construct
  178. */
  179. define('SIMPLEPIE_CONSTRUCT_NONE', 0);
  180. /**
  181. * Text construct
  182. */
  183. define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
  184. /**
  185. * HTML construct
  186. */
  187. define('SIMPLEPIE_CONSTRUCT_HTML', 2);
  188. /**
  189. * XHTML construct
  190. */
  191. define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
  192. /**
  193. * base64-encoded construct
  194. */
  195. define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
  196. /**
  197. * IRI construct
  198. */
  199. define('SIMPLEPIE_CONSTRUCT_IRI', 16);
  200. /**
  201. * A construct that might be HTML
  202. */
  203. define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
  204. /**
  205. * All constructs
  206. */
  207. define('SIMPLEPIE_CONSTRUCT_ALL', 63);
  208. /**
  209. * Don't change case
  210. */
  211. define('SIMPLEPIE_SAME_CASE', 1);
  212. /**
  213. * Change to lowercase
  214. */
  215. define('SIMPLEPIE_LOWERCASE', 2);
  216. /**
  217. * Change to uppercase
  218. */
  219. define('SIMPLEPIE_UPPERCASE', 4);
  220. /**
  221. * PCRE for HTML attributes
  222. */
  223. 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]*');
  224. /**
  225. * PCRE for XML attributes
  226. */
  227. define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
  228. /**
  229. * XML Namespace
  230. */
  231. define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
  232. /**
  233. * Atom 1.0 Namespace
  234. */
  235. define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
  236. /**
  237. * Atom 0.3 Namespace
  238. */
  239. define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
  240. /**
  241. * RDF Namespace
  242. */
  243. define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
  244. /**
  245. * RSS 0.90 Namespace
  246. */
  247. define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
  248. /**
  249. * RSS 1.0 Namespace
  250. */
  251. define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
  252. /**
  253. * RSS 1.0 Content Module Namespace
  254. */
  255. define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
  256. /**
  257. * RSS 2.0 Namespace
  258. * (Stupid, I know, but I'm certain it will confuse people less with support.)
  259. */
  260. define('SIMPLEPIE_NAMESPACE_RSS_20', '');
  261. /**
  262. * DC 1.0 Namespace
  263. */
  264. define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
  265. /**
  266. * DC 1.1 Namespace
  267. */
  268. define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
  269. /**
  270. * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
  271. */
  272. define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
  273. /**
  274. * GeoRSS Namespace
  275. */
  276. define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
  277. /**
  278. * Media RSS Namespace
  279. */
  280. define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
  281. /**
  282. * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
  283. */
  284. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
  285. /**
  286. * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
  287. */
  288. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
  289. /**
  290. * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
  291. */
  292. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
  293. /**
  294. * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
  295. */
  296. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
  297. /**
  298. * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
  299. */
  300. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
  301. /**
  302. * iTunes RSS Namespace
  303. */
  304. define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
  305. /**
  306. * XHTML Namespace
  307. */
  308. define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
  309. /**
  310. * IANA Link Relations Registry
  311. */
  312. define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
  313. /**
  314. * No file source
  315. */
  316. define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
  317. /**
  318. * Remote file source
  319. */
  320. define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
  321. /**
  322. * Local file source
  323. */
  324. define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
  325. /**
  326. * fsockopen() file source
  327. */
  328. define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
  329. /**
  330. * cURL file source
  331. */
  332. define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
  333. /**
  334. * file_get_contents() file source
  335. */
  336. define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
  337. /**
  338. * SimplePie
  339. *
  340. * @package SimplePie
  341. * @subpackage API
  342. */
  343. class SimplePie
  344. {
  345. /**
  346. * @var array Raw data
  347. * @access private
  348. */
  349. public $data = array();
  350. /**
  351. * @var mixed Error string
  352. * @access private
  353. */
  354. public $error;
  355. /**
  356. * @var object Instance of SimplePie_Sanitize (or other class)
  357. * @see SimplePie::set_sanitize_class()
  358. * @access private
  359. */
  360. public $sanitize;
  361. /**
  362. * @var string SimplePie Useragent
  363. * @see SimplePie::set_useragent()
  364. * @access private
  365. */
  366. public $useragent = SIMPLEPIE_USERAGENT;
  367. /**
  368. * @var string Feed URL
  369. * @see SimplePie::set_feed_url()
  370. * @access private
  371. */
  372. public $feed_url;
  373. /**
  374. * @var object Instance of SimplePie_File to use as a feed
  375. * @see SimplePie::set_file()
  376. * @access private
  377. */
  378. public $file;
  379. /**
  380. * @var string Raw feed data
  381. * @see SimplePie::set_raw_data()
  382. * @access private
  383. */
  384. public $raw_data;
  385. /**
  386. * @var int Timeout for fetching remote files
  387. * @see SimplePie::set_timeout()
  388. * @access private
  389. */
  390. public $timeout = 10;
  391. /**
  392. * @var bool Forces fsockopen() to be used for remote files instead
  393. * of cURL, even if a new enough version is installed
  394. * @see SimplePie::force_fsockopen()
  395. * @access private
  396. */
  397. public $force_fsockopen = false;
  398. /**
  399. * @var bool Force the given data/URL to be treated as a feed no matter what
  400. * it appears like
  401. * @see SimplePie::force_feed()
  402. * @access private
  403. */
  404. public $force_feed = false;
  405. /**
  406. * @var bool Enable/Disable Caching
  407. * @see SimplePie::enable_cache()
  408. * @access private
  409. */
  410. public $cache = true;
  411. /**
  412. * @var int Cache duration (in seconds)
  413. * @see SimplePie::set_cache_duration()
  414. * @access private
  415. */
  416. public $cache_duration = 3600;
  417. /**
  418. * @var int Auto-discovery cache duration (in seconds)
  419. * @see SimplePie::set_autodiscovery_cache_duration()
  420. * @access private
  421. */
  422. public $autodiscovery_cache_duration = 604800; // 7 Days.
  423. /**
  424. * @var string Cache location (relative to executing script)
  425. * @see SimplePie::set_cache_location()
  426. * @access private
  427. */
  428. public $cache_location = './cache';
  429. /**
  430. * @var string Function that creates the cache filename
  431. * @see SimplePie::set_cache_name_function()
  432. * @access private
  433. */
  434. public $cache_name_function = 'md5';
  435. /**
  436. * @var bool Reorder feed by date descending
  437. * @see SimplePie::enable_order_by_date()
  438. * @access private
  439. */
  440. public $order_by_date = true;
  441. /**
  442. * @var mixed Force input encoding to be set to the follow value
  443. * (false, or anything type-cast to false, disables this feature)
  444. * @see SimplePie::set_input_encoding()
  445. * @access private
  446. */
  447. public $input_encoding = false;
  448. /**
  449. * @var int Feed Autodiscovery Level
  450. * @see SimplePie::set_autodiscovery_level()
  451. * @access private
  452. */
  453. public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
  454. /**
  455. * Class registry object
  456. *
  457. * @var SimplePie_Registry
  458. */
  459. public $registry;
  460. /**
  461. * @var int Maximum number of feeds to check with autodiscovery
  462. * @see SimplePie::set_max_checked_feeds()
  463. * @access private
  464. */
  465. public $max_checked_feeds = 10;
  466. /**
  467. * @var array All the feeds found during the autodiscovery process
  468. * @see SimplePie::get_all_discovered_feeds()
  469. * @access private
  470. */
  471. public $all_discovered_feeds = array();
  472. /**
  473. * @var string Web-accessible path to the handler_image.php file.
  474. * @see SimplePie::set_image_handler()
  475. * @access private
  476. */
  477. public $image_handler = '';
  478. /**
  479. * @var array Stores the URLs when multiple feeds are being initialized.
  480. * @see SimplePie::set_feed_url()
  481. * @access private
  482. */
  483. public $multifeed_url = array();
  484. /**
  485. * @var array Stores SimplePie objects when multiple feeds initialized.
  486. * @access private
  487. */
  488. public $multifeed_objects = array();
  489. /**
  490. * @var array Stores the get_object_vars() array for use with multifeeds.
  491. * @see SimplePie::set_feed_url()
  492. * @access private
  493. */
  494. public $config_settings = null;
  495. /**
  496. * @var integer Stores the number of items to return per-feed with multifeeds.
  497. * @see SimplePie::set_item_limit()
  498. * @access private
  499. */
  500. public $item_limit = 0;
  501. /**
  502. * @var array Stores the default attributes to be stripped by strip_attributes().
  503. * @see SimplePie::strip_attributes()
  504. * @access private
  505. */
  506. public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
  507. /**
  508. * @var array Stores the default tags to be stripped by strip_htmltags().
  509. * @see SimplePie::strip_htmltags()
  510. * @access private
  511. */
  512. public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
  513. /**
  514. * The SimplePie class contains feed level data and options
  515. *
  516. * To use SimplePie, create the SimplePie object with no parameters. You can
  517. * then set configuration options using the provided methods. After setting
  518. * them, you must initialise the feed using $feed->init(). At that point the
  519. * object's methods and properties will be available to you.
  520. *
  521. * Previously, it was possible to pass in the feed URL along with cache
  522. * options directly into the constructor. This has been removed as of 1.3 as
  523. * it caused a lot of confusion.
  524. *
  525. * @since 1.0 Preview Release
  526. */
  527. public function __construct()
  528. {
  529. if (version_compare(PHP_VERSION, '5.2', '<'))
  530. {
  531. trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
  532. die();
  533. }
  534. // Other objects, instances created here so we can set options on them
  535. $this->sanitize = new SimplePie_Sanitize();
  536. $this->registry = new SimplePie_Registry();
  537. if (func_num_args() > 0)
  538. {
  539. trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.');
  540. }
  541. }
  542. /**
  543. * Used for converting object to a string
  544. */
  545. public function __toString()
  546. {
  547. return md5(serialize($this->data));
  548. }
  549. /**
  550. * Remove items that link back to this before destroying this object
  551. */
  552. public function __destruct()
  553. {
  554. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  555. {
  556. if (!empty($this->data['items']))
  557. {
  558. foreach ($this->data['items'] as $item)
  559. {
  560. $item->__destruct();
  561. }
  562. unset($item, $this->data['items']);
  563. }
  564. if (!empty($this->data['ordered_items']))
  565. {
  566. foreach ($this->data['ordered_items'] as $item)
  567. {
  568. $item->__destruct();
  569. }
  570. unset($item, $this->data['ordered_items']);
  571. }
  572. }
  573. }
  574. /**
  575. * Force the given data/URL to be treated as a feed
  576. *
  577. * This tells SimplePie to ignore the content-type provided by the server.
  578. * Be careful when using this option, as it will also disable autodiscovery.
  579. *
  580. * @since 1.1
  581. * @param bool $enable Force the given data/URL to be treated as a feed
  582. */
  583. public function force_feed($enable = false)
  584. {
  585. $this->force_feed = (bool) $enable;
  586. }
  587. /**
  588. * Set the URL of the feed you want to parse
  589. *
  590. * This allows you to enter the URL of the feed you want to parse, or the
  591. * website you want to try to use auto-discovery on. This takes priority
  592. * over any set raw data.
  593. *
  594. * You can set multiple feeds to mash together by passing an array instead
  595. * of a string for the $url. Remember that with each additional feed comes
  596. * additional processing and resources.
  597. *
  598. * @since 1.0 Preview Release
  599. * @see set_raw_data()
  600. * @param string|array $url This is the URL (or array of URLs) that you want to parse.
  601. */
  602. public function set_feed_url($url)
  603. {
  604. $this->multifeed_url = array();
  605. if (is_array($url))
  606. {
  607. foreach ($url as $value)
  608. {
  609. $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
  610. }
  611. }
  612. else
  613. {
  614. $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
  615. }
  616. }
  617. /**
  618. * Set an instance of {@see SimplePie_File} to use as a feed
  619. *
  620. * @param SimplePie_File &$file
  621. * @return bool True on success, false on failure
  622. */
  623. public function set_file(&$file)
  624. {
  625. if ($file instanceof SimplePie_File)
  626. {
  627. $this->feed_url = $file->url;
  628. $this->file =& $file;
  629. return true;
  630. }
  631. return false;
  632. }
  633. /**
  634. * Set the raw XML data to parse
  635. *
  636. * Allows you to use a string of RSS/Atom data instead of a remote feed.
  637. *
  638. * If you have a feed available as a string in PHP, you can tell SimplePie
  639. * to parse that data string instead of a remote feed. Any set feed URL
  640. * takes precedence.
  641. *
  642. * @since 1.0 Beta 3
  643. * @param string $data RSS or Atom data as a string.
  644. * @see set_feed_url()
  645. */
  646. public function set_raw_data($data)
  647. {
  648. $this->raw_data = $data;
  649. }
  650. /**
  651. * Set the the default timeout for fetching remote feeds
  652. *
  653. * This allows you to change the maximum time the feed's server to respond
  654. * and send the feed back.
  655. *
  656. * @since 1.0 Beta 3
  657. * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
  658. */
  659. public function set_timeout($timeout = 10)
  660. {
  661. $this->timeout = (int) $timeout;
  662. }
  663. /**
  664. * Force SimplePie to use fsockopen() instead of cURL
  665. *
  666. * @since 1.0 Beta 3
  667. * @param bool $enable Force fsockopen() to be used
  668. */
  669. public function force_fsockopen($enable = false)
  670. {
  671. $this->force_fsockopen = (bool) $enable;
  672. }
  673. /**
  674. * Enable/disable caching in SimplePie.
  675. *
  676. * This option allows you to disable caching all-together in SimplePie.
  677. * However, disabling the cache can lead to longer load times.
  678. *
  679. * @since 1.0 Preview Release
  680. * @param bool $enable Enable caching
  681. */
  682. public function enable_cache($enable = true)
  683. {
  684. $this->cache = (bool) $enable;
  685. }
  686. /**
  687. * Set the length of time (in seconds) that the contents of a feed will be
  688. * cached
  689. *
  690. * @param int $seconds The feed content cache duration
  691. */
  692. public function set_cache_duration($seconds = 3600)
  693. {
  694. $this->cache_duration = (int) $seconds;
  695. }
  696. /**
  697. * Set the length of time (in seconds) that the autodiscovered feed URL will
  698. * be cached
  699. *
  700. * @param int $seconds The autodiscovered feed URL cache duration.
  701. */
  702. public function set_autodiscovery_cache_duration($seconds = 604800)
  703. {
  704. $this->autodiscovery_cache_duration = (int) $seconds;
  705. }
  706. /**
  707. * Set the file system location where the cached files should be stored
  708. *
  709. * @param string $location The file system location.
  710. */
  711. public function set_cache_location($location = './cache')
  712. {
  713. $this->cache_location = (string) $location;
  714. }
  715. /**
  716. * Set whether feed items should be sorted into reverse chronological order
  717. *
  718. * @param bool $enable Sort as reverse chronological order.
  719. */
  720. public function enable_order_by_date($enable = true)
  721. {
  722. $this->order_by_date = (bool) $enable;
  723. }
  724. /**
  725. * Set the character encoding used to parse the feed
  726. *
  727. * This overrides the encoding reported by the feed, however it will fall
  728. * back to the normal encoding detection if the override fails
  729. *
  730. * @param string $encoding Character encoding
  731. */
  732. public function set_input_encoding($encoding = false)
  733. {
  734. if ($encoding)
  735. {
  736. $this->input_encoding = (string) $encoding;
  737. }
  738. else
  739. {
  740. $this->input_encoding = false;
  741. }
  742. }
  743. /**
  744. * Set how much feed autodiscovery to do
  745. *
  746. * @see SIMPLEPIE_LOCATOR_NONE
  747. * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
  748. * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
  749. * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
  750. * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
  751. * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
  752. * @see SIMPLEPIE_LOCATOR_ALL
  753. * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
  754. */
  755. public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
  756. {
  757. $this->autodiscovery = (int) $level;
  758. }
  759. /**
  760. * Get the class registry
  761. *
  762. * Use this to override SimplePie's default classes
  763. * @see SimplePie_Registry
  764. * @return SimplePie_Registry
  765. */
  766. public function &get_registry()
  767. {
  768. return $this->registry;
  769. }
  770. /**#@+
  771. * Useful when you are overloading or extending SimplePie's default classes.
  772. *
  773. * @deprecated Use {@see get_registry()} instead
  774. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  775. * @param string $class Name of custom class
  776. * @return boolean True on success, false otherwise
  777. */
  778. /**
  779. * Set which class SimplePie uses for caching
  780. */
  781. public function set_cache_class($class = 'SimplePie_Cache')
  782. {
  783. return $this->registry->register('Cache', $class, true);
  784. }
  785. /**
  786. * Set which class SimplePie uses for auto-discovery
  787. */
  788. public function set_locator_class($class = 'SimplePie_Locator')
  789. {
  790. return $this->registry->register('Locator', $class, true);
  791. }
  792. /**
  793. * Set which class SimplePie uses for XML parsing
  794. */
  795. public function set_parser_class($class = 'SimplePie_Parser')
  796. {
  797. return $this->registry->register('Parser', $class, true);
  798. }
  799. /**
  800. * Set which class SimplePie uses for remote file fetching
  801. */
  802. public function set_file_class($class = 'SimplePie_File')
  803. {
  804. return $this->registry->register('File', $class, true);
  805. }
  806. /**
  807. * Set which class SimplePie uses for data sanitization
  808. */
  809. public function set_sanitize_class($class = 'SimplePie_Sanitize')
  810. {
  811. return $this->registry->register('Sanitize', $class, true);
  812. }
  813. /**
  814. * Set which class SimplePie uses for handling feed items
  815. */
  816. public function set_item_class($class = 'SimplePie_Item')
  817. {
  818. return $this->registry->register('Item', $class, true);
  819. }
  820. /**
  821. * Set which class SimplePie uses for handling author data
  822. */
  823. public function set_author_class($class = 'SimplePie_Author')
  824. {
  825. return $this->registry->register('Author', $class, true);
  826. }
  827. /**
  828. * Set which class SimplePie uses for handling category data
  829. */
  830. public function set_category_class($class = 'SimplePie_Category')
  831. {
  832. return $this->registry->register('Category', $class, true);
  833. }
  834. /**
  835. * Set which class SimplePie uses for feed enclosures
  836. */
  837. public function set_enclosure_class($class = 'SimplePie_Enclosure')
  838. {
  839. return $this->registry->register('Enclosure', $class, true);
  840. }
  841. /**
  842. * Set which class SimplePie uses for `<media:text>` captions
  843. */
  844. public function set_caption_class($class = 'SimplePie_Caption')
  845. {
  846. return $this->registry->register('Caption', $class, true);
  847. }
  848. /**
  849. * Set which class SimplePie uses for `<media:copyright>`
  850. */
  851. public function set_copyright_class($class = 'SimplePie_Copyright')
  852. {
  853. return $this->registry->register('Copyright', $class, true);
  854. }
  855. /**
  856. * Set which class SimplePie uses for `<media:credit>`
  857. */
  858. public function set_credit_class($class = 'SimplePie_Credit')
  859. {
  860. return $this->registry->register('Credit', $class, true);
  861. }
  862. /**
  863. * Set which class SimplePie uses for `<media:rating>`
  864. */
  865. public function set_rating_class($class = 'SimplePie_Rating')
  866. {
  867. return $this->registry->register('Rating', $class, true);
  868. }
  869. /**
  870. * Set which class SimplePie uses for `<media:restriction>`
  871. */
  872. public function set_restriction_class($class = 'SimplePie_Restriction')
  873. {
  874. return $this->registry->register('Restriction', $class, true);
  875. }
  876. /**
  877. * Set which class SimplePie uses for content-type sniffing
  878. */
  879. public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
  880. {
  881. return $this->registry->register('Content_Type_Sniffer', $class, true);
  882. }
  883. /**
  884. * Set which class SimplePie uses item sources
  885. */
  886. public function set_source_class($class = 'SimplePie_Source')
  887. {
  888. return $this->registry->register('Source', $class, true);
  889. }
  890. /**#@-*/
  891. /**
  892. * Set the user agent string
  893. *
  894. * @param string $ua New user agent string.
  895. */
  896. public function set_useragent($ua = SIMPLEPIE_USERAGENT)
  897. {
  898. $this->useragent = (string) $ua;
  899. }
  900. /**
  901. * Set callback function to create cache filename with
  902. *
  903. * @param mixed $function Callback function
  904. */
  905. public function set_cache_name_function($function = 'md5')
  906. {
  907. if (is_callable($function))
  908. {
  909. $this->cache_name_function = $function;
  910. }
  911. }
  912. /**
  913. * Set options to make SP as fast as possible
  914. *
  915. * Forgoes a substantial amount of data sanitization in favor of speed. This
  916. * turns SimplePie into a dumb parser of feeds.
  917. *
  918. * @param bool $set Whether to set them or not
  919. */
  920. public function set_stupidly_fast($set = false)
  921. {
  922. if ($set)
  923. {
  924. $this->enable_order_by_date(false);
  925. $this->remove_div(false);
  926. $this->strip_comments(false);
  927. $this->strip_htmltags(false);
  928. $this->strip_attributes(false);
  929. $this->set_image_handler(false);
  930. }
  931. }
  932. /**
  933. * Set maximum number of feeds to check with autodiscovery
  934. *
  935. * @param int $max Maximum number of feeds to check
  936. */
  937. public function set_max_checked_feeds($max = 10)
  938. {
  939. $this->max_checked_feeds = (int) $max;
  940. }
  941. public function remove_div($enable = true)
  942. {
  943. $this->sanitize->remove_div($enable);
  944. }
  945. public function strip_htmltags($tags = '', $encode = null)
  946. {
  947. if ($tags === '')
  948. {
  949. $tags = $this->strip_htmltags;
  950. }
  951. $this->sanitize->strip_htmltags($tags);
  952. if ($encode !== null)
  953. {
  954. $this->sanitize->encode_instead_of_strip($tags);
  955. }
  956. }
  957. public function encode_instead_of_strip($enable = true)
  958. {
  959. $this->sanitize->encode_instead_of_strip($enable);
  960. }
  961. public function strip_attributes($attribs = '')
  962. {
  963. if ($attribs === '')
  964. {
  965. $attribs = $this->strip_attributes;
  966. }
  967. $this->sanitize->strip_attributes($attribs);
  968. }
  969. /**
  970. * Set the output encoding
  971. *
  972. * Allows you to override SimplePie's output to match that of your webpage.
  973. * This is useful for times when your webpages are not being served as
  974. * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
  975. * is similar to {@see set_input_encoding()}.
  976. *
  977. * It should be noted, however, that not all character encodings can support
  978. * all characters. If your page is being served as ISO-8859-1 and you try
  979. * to display a Japanese feed, you'll likely see garbled characters.
  980. * Because of this, it is highly recommended to ensure that your webpages
  981. * are served as UTF-8.
  982. *
  983. * The number of supported character encodings depends on whether your web
  984. * host supports {@link http://php.net/mbstring mbstring},
  985. * {@link http://php.net/iconv iconv}, or both. See
  986. * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
  987. * more information.
  988. *
  989. * @param string $encoding
  990. */
  991. public function set_output_encoding($encoding = 'UTF-8')
  992. {
  993. $this->sanitize->set_output_encoding($encoding);
  994. }
  995. public function strip_comments($strip = false)
  996. {
  997. $this->sanitize->strip_comments($strip);
  998. }
  999. /**
  1000. * Set element/attribute key/value pairs of HTML attributes
  1001. * containing URLs that need to be resolved relative to the feed
  1002. *
  1003. * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
  1004. * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
  1005. * |q|@cite
  1006. *
  1007. * @since 1.0
  1008. * @param array|null $element_attribute Element/attribute key/value pairs, null for default
  1009. */
  1010. public function set_url_replacements($element_attribute = null)
  1011. {
  1012. $this->sanitize->set_url_replacements($element_attribute);
  1013. }
  1014. /**
  1015. * Set the handler to enable the display of cached images.
  1016. *
  1017. * @param str $page Web-accessible path to the handler_image.php file.
  1018. * @param str $qs The query string that the value should be passed to.
  1019. */
  1020. public function set_image_handler($page = false, $qs = 'i')
  1021. {
  1022. if ($page !== false)
  1023. {
  1024. $this->sanitize->set_image_handler($page . '?' . $qs . '=');
  1025. }
  1026. else
  1027. {
  1028. $this->image_handler = '';
  1029. }
  1030. }
  1031. /**
  1032. * Set the limit for items returned per-feed with multifeeds
  1033. *
  1034. * @param integer $limit The maximum number of items to return.
  1035. */
  1036. public function set_item_limit($limit = 0)
  1037. {
  1038. $this->item_limit = (int) $limit;
  1039. }
  1040. /**
  1041. * Initialize the feed object
  1042. *
  1043. * This is what makes everything happen. Period. This is where all of the
  1044. * configuration options get processed, feeds are fetched, cached, and
  1045. * parsed, and all of that other good stuff.
  1046. *
  1047. * @return boolean True if successful, false otherwise
  1048. */
  1049. public function init()
  1050. {
  1051. // Check absolute bare minimum requirements.
  1052. if (!extension_loaded('xml') || !extension_loaded('pcre'))
  1053. {
  1054. return false;
  1055. }
  1056. // Then 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.
  1057. elseif (!extension_loaded('xmlreader'))
  1058. {
  1059. static $xml_is_sane = null;
  1060. if ($xml_is_sane === null)
  1061. {
  1062. $parser_check = xml_parser_create();
  1063. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  1064. xml_parser_free($parser_check);
  1065. $xml_is_sane = isset($values[0]['value']);
  1066. }
  1067. if (!$xml_is_sane)
  1068. {
  1069. return false;
  1070. }
  1071. }
  1072. if (method_exists($this->sanitize, 'set_registry'))
  1073. {
  1074. $this->sanitize->set_registry($this->registry);
  1075. }
  1076. // Pass whatever was set with config options over to the sanitizer.
  1077. // Pass the classes in for legacy support; new classes should use the registry instead
  1078. $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
  1079. $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
  1080. if (!empty($this->multifeed_url))
  1081. {
  1082. $i = 0;
  1083. $success = 0;
  1084. $this->multifeed_objects = array();
  1085. $this->error = array();
  1086. foreach ($this->multifeed_url as $url)
  1087. {
  1088. $this->multifeed_objects[$i] = clone $this;
  1089. $this->multifeed_objects[$i]->set_feed_url($url);
  1090. $single_success = $this->multifeed_objects[$i]->init();
  1091. $success |= $single_success;
  1092. if (!$single_success)
  1093. {
  1094. $this->error[$i] = $this->multifeed_objects[$i]->error();
  1095. }
  1096. $i++;
  1097. }
  1098. return (bool) $success;
  1099. }
  1100. elseif ($this->feed_url === null && $this->raw_data === null)
  1101. {
  1102. return false;
  1103. }
  1104. $this->error = null;
  1105. $this->data = array();
  1106. $this->multifeed_objects = array();
  1107. $cache = false;
  1108. if ($this->feed_url !== null)
  1109. {
  1110. $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
  1111. // Decide whether to enable caching
  1112. if ($this->cache && $parsed_feed_url['scheme'] !== '')
  1113. {
  1114. $cache = $this->registry->call('Cache', 'create', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
  1115. }
  1116. // Fetch the data via SimplePie_File into $this->raw_data
  1117. if (($fetched = $this->fetch_data($cache)) === true)
  1118. {
  1119. return true;
  1120. }
  1121. elseif ($fetched === false) {
  1122. return false;
  1123. }
  1124. list($headers, $sniffed) = $fetched;
  1125. }
  1126. // Set up array of possible encodings
  1127. $encodings = array();
  1128. // First check to see if input has been overridden.
  1129. if ($this->input_encoding !== false)
  1130. {
  1131. $encodings[] = $this->input_encoding;
  1132. }
  1133. $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
  1134. $text_types = array('text/xml', 'text/xml-external-parsed-entity');
  1135. // RFC 3023 (only applies to sniffed content)
  1136. if (isset($sniffed))
  1137. {
  1138. if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
  1139. {
  1140. if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
  1141. {
  1142. $encodings[] = strtoupper($charset[1]);
  1143. }
  1144. $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
  1145. $encodings[] = 'UTF-8';
  1146. }
  1147. elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
  1148. {
  1149. if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
  1150. {
  1151. $encodings[] = $charset[1];
  1152. }
  1153. $encodings[] = 'US-ASCII';
  1154. }
  1155. // Text MIME-type default
  1156. elseif (substr($sniffed, 0, 5) === 'text/')
  1157. {
  1158. $encodings[] = 'US-ASCII';
  1159. }
  1160. }
  1161. // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
  1162. $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
  1163. $encodings[] = 'UTF-8';
  1164. $encodings[] = 'ISO-8859-1';
  1165. // There's no point in trying an encoding twice
  1166. $encodings = array_unique($encodings);
  1167. // Loop through each possible encoding, till we return something, or run out of possibilities
  1168. foreach ($encodings as $encoding)
  1169. {
  1170. // Change the encoding to UTF-8 (as we always use UTF-8 internally)
  1171. if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
  1172. {
  1173. // Create new parser
  1174. $parser = $this->registry->create('Parser');
  1175. // If it's parsed fine
  1176. if ($parser->parse($utf8_data, 'UTF-8'))
  1177. {
  1178. $this->data = $parser->get_data();
  1179. if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
  1180. {
  1181. $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
  1182. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1183. return false;
  1184. }
  1185. if (isset($headers))
  1186. {
  1187. $this->data['headers'] = $headers;
  1188. }
  1189. $this->data['build'] = SIMPLEPIE_BUILD;
  1190. // Cache the file if caching is enabled
  1191. if ($cache && !$cache->save($this))
  1192. {
  1193. trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
  1194. }
  1195. return true;
  1196. }
  1197. }
  1198. }
  1199. if (isset($parser))
  1200. {
  1201. // We have an error, just set SimplePie_Misc::error to it and quit
  1202. $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());
  1203. }
  1204. else
  1205. {
  1206. $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.';
  1207. }
  1208. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1209. return false;
  1210. }
  1211. /**
  1212. * Fetch the data via SimplePie_File
  1213. *
  1214. * If the data is already cached, attempt to fetch it from there instead
  1215. * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
  1216. * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
  1217. */
  1218. protected function fetch_data(&$cache)
  1219. {
  1220. // If it's enabled, use the cache
  1221. if ($cache)
  1222. {
  1223. // Load the Cache
  1224. $this->data = $cache->load();
  1225. if (!empty($this->data))
  1226. {
  1227. // If the cache is for an outdated build of SimplePie
  1228. if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
  1229. {
  1230. $cache->unlink();
  1231. $this->data = array();
  1232. }
  1233. // If we've hit a collision just rerun it with caching disabled
  1234. elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
  1235. {
  1236. $cache = false;
  1237. $this->data = array();
  1238. }
  1239. // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
  1240. elseif (isset($this->data['feed_url']))
  1241. {
  1242. // If the autodiscovery cache is still valid use it.
  1243. if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
  1244. {
  1245. // Do not need to do feed autodiscovery yet.
  1246. if ($this->data['feed_url'] !== $this->data['url'])
  1247. {
  1248. $this->set_feed_url($this->data['feed_url']);
  1249. return $this->init();
  1250. }
  1251. $cache->unlink();
  1252. $this->data = array();
  1253. }
  1254. }
  1255. // Check if the cache has been updated
  1256. elseif ($cache->mtime() + $this->cache_duration < time())
  1257. {
  1258. // If we have last-modified and/or etag set
  1259. if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
  1260. {
  1261. $headers = array(
  1262. 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
  1263. );
  1264. if (isset($this->data['headers']['last-modified']))
  1265. {
  1266. $headers['if-modified-since'] = $this->data['headers']['last-modified'];
  1267. }
  1268. if (isset($this->data['headers']['etag']))
  1269. {
  1270. $headers['if-none-match'] = $this->data['headers']['etag'];
  1271. }
  1272. $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
  1273. if ($file->success)
  1274. {
  1275. if ($file->status_code === 304)
  1276. {
  1277. $cache->touch();
  1278. return true;
  1279. }
  1280. }
  1281. else
  1282. {
  1283. unset($file);
  1284. }
  1285. }
  1286. }
  1287. // If the cache is still valid, just return true
  1288. else
  1289. {
  1290. $this->raw_data = false;
  1291. return true;
  1292. }
  1293. }
  1294. // If the cache is empty, delete it
  1295. else
  1296. {
  1297. $cache->unlink();
  1298. $this->data = array();
  1299. }
  1300. }
  1301. // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
  1302. if (!isset($file))
  1303. {
  1304. if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
  1305. {
  1306. $file =& $this->file;
  1307. }
  1308. else
  1309. {
  1310. $headers = array(
  1311. 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
  1312. );
  1313. $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
  1314. }
  1315. }
  1316. // If the file connection has an error, set SimplePie::error to that and quit
  1317. if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
  1318. {
  1319. $this->error = $file->error;
  1320. return !empty($this->data);
  1321. }
  1322. if (!$this->force_feed)
  1323. {
  1324. // Check if the supplied URL is a feed, if it isn't, look for it.
  1325. $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
  1326. if (!$locate->is_feed($file))
  1327. {
  1328. // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
  1329. unset($file);
  1330. if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
  1331. {
  1332. $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed.";
  1333. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1334. return false;
  1335. }
  1336. if ($cache)
  1337. {
  1338. $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
  1339. if (!$cache->save($this))
  1340. {
  1341. trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
  1342. }
  1343. $cache = $this->registry->call('Cache', 'create', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
  1344. }
  1345. $this->feed_url = $file->url;
  1346. }
  1347. $locate = null;
  1348. }
  1349. $this->raw_data = $file->body;
  1350. $headers = $file->headers;
  1351. $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
  1352. $sniffed = $sniffer->get_type();
  1353. return array($headers, $sniffed);
  1354. }
  1355. /**
  1356. * Get the error message for the occured error
  1357. *
  1358. * @return string|array Error message, or array of messages for multifeeds
  1359. */
  1360. public function error()
  1361. {
  1362. return $this->error;
  1363. }
  1364. /**
  1365. * Get the raw XML
  1366. *
  1367. * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
  1368. * the data instead of printing it.
  1369. *
  1370. * @return string|boolean Raw XML data, false if the cache is used
  1371. */
  1372. public function get_raw_data()
  1373. {
  1374. return $this->raw_data;
  1375. }
  1376. /**
  1377. * Get the character encoding used for output
  1378. *
  1379. * @since Preview Release
  1380. * @return string
  1381. */
  1382. public function get_encoding()
  1383. {
  1384. return $this->sanitize->output_encoding;
  1385. }
  1386. /**
  1387. * Send the content-type header with correct encoding
  1388. *
  1389. * This method ensures that the SimplePie-enabled page is being served with
  1390. * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
  1391. * and character encoding HTTP headers (character encoding determined by the
  1392. * {@see set_output_encoding} config option).
  1393. *
  1394. * This won't work properly if any content or whitespace has already been
  1395. * sent to the browser, because it relies on PHP's
  1396. * {@link http://php.net/header header()} function, and these are the
  1397. * circumstances under which the function works.
  1398. *
  1399. * Because it's setting these settings for the entire page (as is the nature
  1400. * of HTTP headers), this should only be used once per page (again, at the
  1401. * top).
  1402. *
  1403. * @param string $mime MIME type to serve the page as
  1404. */
  1405. public function handle_content_type($mime = 'text/html')
  1406. {
  1407. if (!headers_sent())
  1408. {
  1409. $header = "Content-type: $mime;";
  1410. if ($this->get_encoding())
  1411. {
  1412. $header .= ' charset=' . $this->get_encoding();
  1413. }
  1414. else
  1415. {
  1416. $header .= ' charset=UTF-8';
  1417. }
  1418. header($header);
  1419. }
  1420. }
  1421. /**
  1422. * Get the type of the feed
  1423. *
  1424. * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
  1425. * using {@link http://php.net/language.operators.bitwise bitwise operators}
  1426. *
  1427. * @since 0.8 (usage changed to using constants in 1.0)
  1428. * @see SIMPLEPIE_TYPE_NONE Unknown.
  1429. * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
  1430. * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
  1431. * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
  1432. * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
  1433. * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
  1434. * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
  1435. * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
  1436. * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
  1437. * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
  1438. * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
  1439. * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
  1440. * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
  1441. * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
  1442. * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
  1443. * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
  1444. * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
  1445. * @return int SIMPLEPIE_TYPE_* constant
  1446. */
  1447. public function get_type()
  1448. {
  1449. if (!isset($this->data['type']))
  1450. {
  1451. $this->data['type'] = SIMPLEPIE_TYPE_ALL;
  1452. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
  1453. {
  1454. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
  1455. }
  1456. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
  1457. {
  1458. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
  1459. }
  1460. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
  1461. {
  1462. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
  1463. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
  1464. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
  1465. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
  1466. {
  1467. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
  1468. }
  1469. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
  1470. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
  1471. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
  1472. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
  1473. {
  1474. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
  1475. }
  1476. }
  1477. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
  1478. {
  1479. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
  1480. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  1481. {
  1482. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  1483. {
  1484. case '0.91':
  1485. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
  1486. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  1487. {
  1488. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  1489. {
  1490. case '0':
  1491. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
  1492. break;
  1493. case '24':
  1494. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
  1495. break;
  1496. }
  1497. }
  1498. break;
  1499. case '0.92':
  1500. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
  1501. break;
  1502. case '0.93':
  1503. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
  1504. break;
  1505. case '0.94':
  1506. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
  1507. break;
  1508. case '2.0':
  1509. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
  1510. break;
  1511. }
  1512. }
  1513. }
  1514. else
  1515. {
  1516. $this->data['type'] = SIMPLEPIE_TYPE_NONE;
  1517. }
  1518. }
  1519. return $this->data['type'];
  1520. }
  1521. /**
  1522. * Get the URL for the feed
  1523. *
  1524. * May or may not be different from the URL passed to {@see set_feed_url()},
  1525. * depending on whether auto-discovery was used.
  1526. *
  1527. * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
  1528. * @todo If we have a perm redirect we should return the new URL
  1529. * @todo When we make the above change, let's support <itunes:new-feed-url> as well
  1530. * @todo Also, |atom:link|@rel=self
  1531. * @return string|null
  1532. */
  1533. public function subscribe_url()
  1534. {
  1535. if ($this->feed_url !== null)
  1536. {
  1537. return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
  1538. }
  1539. else
  1540. {
  1541. return null;
  1542. }
  1543. }
  1544. /**
  1545. * Get data for an feed-level element
  1546. *
  1547. * This method allows you to get access to ANY element/attribute that is a
  1548. * sub-element of the opening feed tag.
  1549. *
  1550. * The return value is an indexed array of elements matching the given
  1551. * namespace and tag name. Each element has `attribs`, `data` and `child`
  1552. * subkeys. For `attribs` and `child`, these contain namespace subkeys.
  1553. * `attribs` then has one level of associative name => value data (where
  1554. * `value` is a string) after the namespace. `child` has tag-indexed keys
  1555. * after the namespace, each member of which is an indexed array matching
  1556. * this same format.
  1557. *
  1558. * For example:
  1559. * <pre>
  1560. * // This is probably a bad example because we already support
  1561. * // <media:content> natively, but it shows you how to parse through
  1562. * // the nodes.
  1563. * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
  1564. * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
  1565. * $file = $content[0]['attribs']['']['url'];
  1566. * echo $file;
  1567. * </pre>
  1568. *
  1569. * @since 1.0
  1570. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1571. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1572. * @param string $tag Tag name
  1573. * @return array
  1574. */
  1575. public function get_feed_tags($namespace, $tag)
  1576. {
  1577. $type = $this->get_type();
  1578. if ($type & SIMPLEPIE_TYPE_ATOM_10)
  1579. {
  1580. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
  1581. {
  1582. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
  1583. }
  1584. }
  1585. if ($type & SIMPLEPIE_TYPE_ATOM_03)
  1586. {
  1587. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
  1588. {
  1589. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
  1590. }
  1591. }
  1592. if ($type & SIMPLEPIE_TYPE_RSS_RDF)
  1593. {
  1594. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
  1595. {
  1596. return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
  1597. }
  1598. }
  1599. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1600. {
  1601. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
  1602. {
  1603. return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
  1604. }
  1605. }
  1606. return null;
  1607. }
  1608. /**
  1609. * Get data for an channel-level element
  1610. *
  1611. * This method allows you to get access to ANY element/attribute in the
  1612. * channel/header section of the feed.
  1613. *
  1614. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  1615. *
  1616. * @since 1.0
  1617. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1618. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1619. * @param string $tag Tag name
  1620. * @return array
  1621. */
  1622. public function get_channel_tags($namespace, $tag)
  1623. {
  1624. $type = $this->get_type();
  1625. if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
  1626. {
  1627. if ($return = $this->get_feed_tags($namespace, $tag))
  1628. {
  1629. return $return;
  1630. }
  1631. }
  1632. if ($type & SIMPLEPIE_TYPE_RSS_10)
  1633. {
  1634. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
  1635. {
  1636. if (isset($channel[0]['child'][$namespace][$tag]))
  1637. {
  1638. return $channel[0]['child'][$namespace][$tag];
  1639. }
  1640. }
  1641. }
  1642. if ($type & SIMPLEPIE_TYPE_RSS_090)
  1643. {
  1644. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
  1645. {
  1646. if (isset($channel[0]['child'][$namespace][$tag]))
  1647. {
  1648. return $channel[0]['child'][$namespace][$tag];
  1649. }
  1650. }
  1651. }
  1652. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1653. {
  1654. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
  1655. {
  1656. if (isset($channel[0]['child'][$namespace][$tag]))
  1657. {
  1658. return $channel[0]['child'][$namespace][$tag];
  1659. }
  1660. }
  1661. }
  1662. return null;
  1663. }
  1664. /**
  1665. * Get data for an channel-level element
  1666. *
  1667. * This method allows you to get access to ANY element/attribute in the
  1668. * image/logo section of the feed.
  1669. *
  1670. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  1671. *
  1672. * @since 1.0
  1673. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1674. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1675. * @param string $tag Tag name
  1676. * @return array
  1677. */
  1678. public function get_image_tags($namespace, $tag)
  1679. {
  1680. $type = $this->get_type();
  1681. if ($type & SIMPLEPIE_TYPE_RSS_10)
  1682. {
  1683. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
  1684. {
  1685. if (isset($image[0]['child'][$namespace][$tag]))
  1686. {
  1687. return $image[0]['child'][$namespace][$tag];
  1688. }
  1689. }
  1690. }
  1691. if ($type & SIMPLEPIE_TYPE_RSS_090)
  1692. {
  1693. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
  1694. {
  1695. if (isset($image[0]['child'][$namespace][$tag]))
  1696. {
  1697. return $image[0]['child'][$namespace][$tag];
  1698. }
  1699. }
  1700. }
  1701. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1702. {
  1703. if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
  1704. {
  1705. if (isset($image[0]['child'][$namespace][$tag]))
  1706. {
  1707. return $image[0]['child'][$namespace][$tag];
  1708. }
  1709. }
  1710. }
  1711. return null;
  1712. }
  1713. /**
  1714. * Get the base URL value from the feed
  1715. *
  1716. * Uses `<xml:base>` if available, otherwise uses the first link in the
  1717. * feed, or failing that, the URL of the feed itself.
  1718. *
  1719. * @see get_link
  1720. * @see subscribe_url
  1721. *
  1722. * @param array $element
  1723. * @return string
  1724. */
  1725. public function get_base($element = array())
  1726. {
  1727. if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
  1728. {
  1729. return $element['xml_base'];
  1730. }
  1731. elseif ($this->get_link() !== null)
  1732. {
  1733. return $this->get_link();
  1734. }
  1735. else
  1736. {
  1737. return $this->subscribe_url();
  1738. }
  1739. }
  1740. /**
  1741. * Sanitize feed data
  1742. *
  1743. * @access private
  1744. * @see SimplePie_Sanitize::sanitize()
  1745. * @param string $data Data to sanitize
  1746. * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
  1747. * @param string $base Base URL to resolve URLs against
  1748. * @return string Sanitized data
  1749. */
  1750. public function sanitize($data, $type, $base = '')
  1751. {
  1752. return $this->sanitize->sanitize($data, $type, $base);
  1753. }
  1754. /**
  1755. * Get the title of the feed
  1756. *
  1757. * Uses `<atom:title>`, `<title>` or `<dc:title>`
  1758. *
  1759. * @since 1.0 (previously called `get_feed_title` since 0.8)
  1760. * @return string|null
  1761. */
  1762. public function get_title()
  1763. {
  1764. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  1765. {
  1766. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  1767. }
  1768. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  1769. {
  1770. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  1771. }
  1772. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  1773. {
  1774. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1775. }
  1776. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  1777. {
  1778. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1779. }
  1780. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  1781. {
  1782. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1783. }
  1784. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  1785. {
  1786. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1787. }
  1788. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  1789. {
  1790. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1791. }
  1792. else
  1793. {
  1794. return null;
  1795. }
  1796. }
  1797. /**
  1798. * Get a category for the feed
  1799. *
  1800. * @since Unknown
  1801. * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
  1802. * @return SimplePie_Category|null
  1803. */
  1804. public function get_category($key = 0)
  1805. {
  1806. $categories = $this->get_categories();
  1807. if (isset($categories[$key]))
  1808. {
  1809. return $categories[$key];
  1810. }
  1811. else
  1812. {
  1813. return null;
  1814. }
  1815. }
  1816. /**
  1817. * Get all categories for the feed
  1818. *
  1819. * Uses `<atom:category>`, `<category>` or `<dc:subject>`
  1820. *
  1821. * @since Unknown
  1822. * @return array|null List of {@see SimplePie_Category} objects
  1823. */
  1824. public function get_categories()
  1825. {
  1826. $categories = array();
  1827. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  1828. {
  1829. $term = null;
  1830. $scheme = null;
  1831. $label = null;
  1832. if (isset($category['attribs']['']['term']))
  1833. {
  1834. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  1835. }
  1836. if (isset($category['attribs']['']['scheme']))
  1837. {
  1838. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  1839. }
  1840. if (isset($category['attribs']['']['label']))
  1841. {
  1842. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  1843. }
  1844. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  1845. }
  1846. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  1847. {
  1848. // This is really the label, but keep this as the term also for BC.
  1849. // Label will also work on retrieving because that falls back to term.
  1850. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1851. if (isset($category['attribs']['']['domain']))
  1852. {
  1853. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  1854. }
  1855. else
  1856. {
  1857. $scheme = null;
  1858. }
  1859. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  1860. }
  1861. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  1862. {
  1863. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1864. }
  1865. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  1866. {
  1867. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1868. }
  1869. if (!empty($categories))
  1870. {
  1871. return array_unique($categories);
  1872. }
  1873. else
  1874. {
  1875. return null;
  1876. }
  1877. }
  1878. /**
  1879. * Get an author for the feed
  1880. *
  1881. * @since 1.1
  1882. * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
  1883. * @return SimplePie_Author|null
  1884. */
  1885. public function get_author($key = 0)
  1886. {
  1887. $authors = $this->get_authors();
  1888. if (isset($authors[$key]))
  1889. {
  1890. return $authors[$key];
  1891. }
  1892. else
  1893. {
  1894. return null;
  1895. }
  1896. }
  1897. /**
  1898. * Get all authors for the feed
  1899. *
  1900. * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
  1901. *
  1902. * @since 1.1
  1903. * @return array|null List of {@see SimplePie_Author} objects
  1904. */
  1905. public function get_authors()
  1906. {
  1907. $authors = array();
  1908. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  1909. {
  1910. $name = null;
  1911. $uri = null;
  1912. $email = null;
  1913. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  1914. {
  1915. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1916. }
  1917. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  1918. {
  1919. $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]));
  1920. }
  1921. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  1922. {
  1923. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1924. }
  1925. if ($name !== null || $email !== null || $uri !== null)
  1926. {
  1927. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  1928. }
  1929. }
  1930. if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  1931. {
  1932. $name = null;
  1933. $url = null;
  1934. $email = null;
  1935. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  1936. {
  1937. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1938. }
  1939. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  1940. {
  1941. $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]));
  1942. }
  1943. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  1944. {
  1945. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1946. }
  1947. if ($name !== null || $email !== null || $url !== null)
  1948. {
  1949. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  1950. }
  1951. }
  1952. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  1953. {
  1954. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1955. }
  1956. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  1957. {
  1958. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1959. }
  1960. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  1961. {
  1962. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1963. }
  1964. if (!empty($authors))
  1965. {
  1966. return array_unique($authors);
  1967. }
  1968. else
  1969. {
  1970. return null;
  1971. }
  1972. }
  1973. /**
  1974. * Get a contributor for the feed
  1975. *
  1976. * @since 1.1
  1977. * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
  1978. * @return SimplePie_Author|null
  1979. */
  1980. public function get_contributor($key = 0)
  1981. {
  1982. $contributors = $this->get_contributors();
  1983. if (isset($contributors[$key]))
  1984. {
  1985. return $contributors[$key];
  1986. }
  1987. else
  1988. {
  1989. return null;
  1990. }
  1991. }
  1992. /**
  1993. * Get all contributors for the feed
  1994. *
  1995. * Uses `<atom:contributor>`
  1996. *
  1997. * @since 1.1
  1998. * @return array|null List of {@see SimplePie_Author} objects
  1999. */
  2000. public function get_contributors()
  2001. {
  2002. $contributors = array();
  2003. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  2004. {
  2005. $name = null;
  2006. $uri = null;
  2007. $email = null;
  2008. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  2009. {
  2010. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2011. }
  2012. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  2013. {
  2014. $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]));
  2015. }
  2016. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  2017. {
  2018. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2019. }
  2020. if ($name !== null || $email !== null || $uri !== null)
  2021. {
  2022. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  2023. }
  2024. }
  2025. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  2026. {
  2027. $name = null;
  2028. $url = null;
  2029. $email = null;
  2030. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  2031. {
  2032. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2033. }
  2034. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  2035. {
  2036. $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]));
  2037. }
  2038. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  2039. {
  2040. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2041. }
  2042. if ($name !== null || $email !== null || $url !== null)
  2043. {
  2044. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  2045. }
  2046. }
  2047. if (!empty($contributors))
  2048. {
  2049. return array_unique($contributors);
  2050. }
  2051. else
  2052. {
  2053. return null;
  2054. }
  2055. }
  2056. /**
  2057. * Get a single link for the feed
  2058. *
  2059. * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
  2060. * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
  2061. * @param string $rel The relationship of the link to return
  2062. * @return string|null Link URL
  2063. */
  2064. public function get_link($key = 0, $rel = 'alternate')
  2065. {
  2066. $links = $this->get_links($rel);
  2067. if (isset($links[$key]))
  2068. {
  2069. return $links[$key];
  2070. }
  2071. else
  2072. {
  2073. return null;
  2074. }
  2075. }
  2076. /**
  2077. * Get the permalink for the item
  2078. *
  2079. * Returns the first link available with a relationship of "alternate".
  2080. * Identical to {@see get_link()} with key 0
  2081. *
  2082. * @see get_link
  2083. * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
  2084. * @internal Added for parity between the parent-level and the item/entry-level.
  2085. * @return string|null Link URL
  2086. */
  2087. public function get_permalink()
  2088. {
  2089. return $this->get_link(0);
  2090. }
  2091. /**
  2092. * Get all links for the feed
  2093. *
  2094. * Uses `<atom:link>` or `<link>`
  2095. *
  2096. * @since Beta 2
  2097. * @param string $rel The relationship of links to return
  2098. * @return array|null Links found for the feed (strings)
  2099. */
  2100. public function get_links($rel = 'alternate')
  2101. {
  2102. if (!isset($this->data['links']))
  2103. {
  2104. $this->data['links'] = array();
  2105. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  2106. {
  2107. foreach ($links as $link)
  2108. {
  2109. if (isset($link['attribs']['']['href']))
  2110. {
  2111. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2112. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2113. }
  2114. }
  2115. }
  2116. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  2117. {
  2118. foreach ($links as $link)
  2119. {
  2120. if (isset($link['attribs']['']['href']))
  2121. {
  2122. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2123. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2124. }
  2125. }
  2126. }
  2127. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  2128. {
  2129. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2130. }
  2131. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  2132. {
  2133. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2134. }
  2135. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  2136. {
  2137. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2138. }
  2139. $keys = array_keys($this->data['links']);
  2140. foreach ($keys as $key)
  2141. {
  2142. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  2143. {
  2144. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  2145. {
  2146. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  2147. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  2148. }
  2149. else
  2150. {
  2151. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  2152. }
  2153. }
  2154. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  2155. {
  2156. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  2157. }
  2158. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  2159. }
  2160. }
  2161. if (isset($this->data['links'][$rel]))
  2162. {
  2163. return $this->data['links'][$rel];
  2164. }
  2165. else
  2166. {
  2167. return null;
  2168. }
  2169. }
  2170. public function get_all_discovered_feeds()
  2171. {
  2172. return $this->all_discovered_feeds;
  2173. }
  2174. /**
  2175. * Get the content for the item
  2176. *
  2177. * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
  2178. * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
  2179. *
  2180. * @since 1.0 (previously called `get_feed_description()` since 0.8)
  2181. * @return string|null
  2182. */
  2183. public function get_description()
  2184. {
  2185. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  2186. {
  2187. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2188. }
  2189. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  2190. {
  2191. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2192. }
  2193. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  2194. {
  2195. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  2196. }
  2197. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  2198. {
  2199. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  2200. }
  2201. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  2202. {
  2203. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2204. }
  2205. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  2206. {
  2207. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2208. }
  2209. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  2210. {
  2211. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2212. }
  2213. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  2214. {
  2215. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2216. }
  2217. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  2218. {
  2219. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2220. }
  2221. else
  2222. {
  2223. return null;
  2224. }
  2225. }
  2226. /**
  2227. * Get the copyright info for the feed
  2228. *
  2229. * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
  2230. *
  2231. * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
  2232. * @return string|null
  2233. */
  2234. public function get_copyright()
  2235. {
  2236. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  2237. {
  2238. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2239. }
  2240. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  2241. {
  2242. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2243. }
  2244. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  2245. {
  2246. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2247. }
  2248. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  2249. {
  2250. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2251. }
  2252. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  2253. {
  2254. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2255. }
  2256. else
  2257. {
  2258. return null;
  2259. }
  2260. }
  2261. /**
  2262. * Get the language for the feed
  2263. *
  2264. * Uses `<language>`, `<dc:language>`, or @xml_lang
  2265. *
  2266. * @since 1.0 (previously called `get_feed_language()` since 0.8)
  2267. * @return string|null
  2268. */
  2269. public function get_language()
  2270. {
  2271. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  2272. {
  2273. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2274. }
  2275. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  2276. {
  2277. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2278. }
  2279. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  2280. {
  2281. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2282. }
  2283. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
  2284. {
  2285. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2286. }
  2287. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
  2288. {
  2289. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2290. }
  2291. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
  2292. {
  2293. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2294. }
  2295. elseif (isset($this->data['headers']['content-language']))
  2296. {
  2297. return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
  2298. }
  2299. else
  2300. {
  2301. return null;
  2302. }
  2303. }
  2304. /**
  2305. * Get the latitude coordinates for the item
  2306. *
  2307. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  2308. *
  2309. * Uses `<geo:lat>` or `<georss:point>`
  2310. *
  2311. * @since 1.0
  2312. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  2313. * @link http://www.georss.org/ GeoRSS
  2314. * @return string|null
  2315. */
  2316. public function get_latitude()
  2317. {
  2318. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  2319. {
  2320. return (float) $return[0]['data'];
  2321. }
  2322. elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
  2323. {
  2324. return (float) $match[1];
  2325. }
  2326. else
  2327. {
  2328. return null;
  2329. }
  2330. }
  2331. /**
  2332. * Get the longitude coordinates for the feed
  2333. *
  2334. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  2335. *
  2336. * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
  2337. *
  2338. * @since 1.0
  2339. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  2340. * @link http://www.georss.org/ GeoRSS
  2341. * @return string|null
  2342. */
  2343. public function get_longitude()
  2344. {
  2345. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  2346. {
  2347. return (float) $return[0]['data'];
  2348. }
  2349. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  2350. {
  2351. return (float) $return[0]['data'];
  2352. }
  2353. elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
  2354. {
  2355. return (float) $match[2];
  2356. }
  2357. else
  2358. {
  2359. return null;
  2360. }
  2361. }
  2362. /**
  2363. * Get the feed logo's title
  2364. *
  2365. * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
  2366. *
  2367. * Uses `<image><title>` or `<image><dc:title>`
  2368. *
  2369. * @return string|null
  2370. */
  2371. public function get_image_title()
  2372. {
  2373. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  2374. {
  2375. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2376. }
  2377. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  2378. {
  2379. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2380. }
  2381. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  2382. {
  2383. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2384. }
  2385. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  2386. {
  2387. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2388. }
  2389. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  2390. {
  2391. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2392. }
  2393. else
  2394. {
  2395. return null;
  2396. }
  2397. }
  2398. /**
  2399. * Get the feed logo's URL
  2400. *
  2401. * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
  2402. * have a "feed logo" URL. This points directly to the image itself.
  2403. *
  2404. * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
  2405. * `<image><title>` or `<image><dc:title>`
  2406. *
  2407. * @return string|null
  2408. */
  2409. public function get_image_url()
  2410. {
  2411. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
  2412. {
  2413. return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
  2414. }
  2415. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  2416. {
  2417. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2418. }
  2419. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  2420. {
  2421. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2422. }
  2423. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
  2424. {
  2425. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2426. }
  2427. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
  2428. {
  2429. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2430. }
  2431. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2432. {
  2433. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2434. }
  2435. else
  2436. {
  2437. return null;
  2438. }
  2439. }
  2440. /**
  2441. * Get the feed logo's link
  2442. *
  2443. * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
  2444. * points to a human-readable page that the image should link to.
  2445. *
  2446. * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
  2447. * `<image><title>` or `<image><dc:title>`
  2448. *
  2449. * @return string|null
  2450. */
  2451. public function get_image_link()
  2452. {
  2453. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  2454. {
  2455. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2456. }
  2457. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  2458. {
  2459. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2460. }
  2461. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  2462. {
  2463. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2464. }
  2465. else
  2466. {
  2467. return null;
  2468. }
  2469. }
  2470. /**
  2471. * Get the feed logo's link
  2472. *
  2473. * RSS 2.0 feeds are allowed to have a "feed logo" width.
  2474. *
  2475. * Uses `<image><width>` or defaults to 88.0 if no width is specified and
  2476. * the feed is an RSS 2.0 feed.
  2477. *
  2478. * @return int|float|null
  2479. */
  2480. public function get_image_width()
  2481. {
  2482. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
  2483. {
  2484. return round($return[0]['data']);
  2485. }
  2486. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2487. {
  2488. return 88.0;
  2489. }
  2490. else
  2491. {
  2492. return null;
  2493. }
  2494. }
  2495. /**
  2496. * Get the feed logo's height
  2497. *
  2498. * RSS 2.0 feeds are allowed to have a "feed logo" height.
  2499. *
  2500. * Uses `<image><height>` or defaults to 31.0 if no height is specified and
  2501. * the feed is an RSS 2.0 feed.
  2502. *
  2503. * @return int|float|null
  2504. */
  2505. public function get_image_height()
  2506. {
  2507. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
  2508. {
  2509. return round($return[0]['data']);
  2510. }
  2511. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2512. {
  2513. return 31.0;
  2514. }
  2515. else
  2516. {
  2517. return null;
  2518. }
  2519. }
  2520. /**
  2521. * Get the number of items in the feed
  2522. *
  2523. * This is well-suited for {@link http://php.net/for for()} loops with
  2524. * {@see get_item()}
  2525. *
  2526. * @param int $max Maximum value to return. 0 for no limit
  2527. * @return int Number of items in the feed
  2528. */
  2529. public function get_item_quantity($max = 0)
  2530. {
  2531. $max = (int) $max;
  2532. $qty = count($this->get_items());
  2533. if ($max === 0)
  2534. {
  2535. return $qty;
  2536. }
  2537. else
  2538. {
  2539. return ($qty > $max) ? $max : $qty;
  2540. }
  2541. }
  2542. /**
  2543. * Get a single item from the feed
  2544. *
  2545. * This is better suited for {@link http://php.net/for for()} loops, whereas
  2546. * {@see get_items()} is better suited for
  2547. * {@link http://php.net/foreach foreach()} loops.
  2548. *
  2549. * @see get_item_quantity()
  2550. * @since Beta 2
  2551. * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
  2552. * @return SimplePie_Item|null
  2553. */
  2554. public function get_item($key = 0)
  2555. {
  2556. $items = $this->get_items();
  2557. if (isset($items[$key]))
  2558. {
  2559. return $items[$key];
  2560. }
  2561. else
  2562. {
  2563. return null;
  2564. }
  2565. }
  2566. /**
  2567. * Get all items from the feed
  2568. *
  2569. * This is better suited for {@link http://php.net/for for()} loops, whereas
  2570. * {@see get_items()} is better suited for
  2571. * {@link http://php.net/foreach foreach()} loops.
  2572. *
  2573. * @see get_item_quantity
  2574. * @since Beta 2
  2575. * @param int $start Index to start at
  2576. * @param int $end Number of items to return. 0 for all items after `$start`
  2577. * @return array|null List of {@see SimplePie_Item} objects
  2578. */
  2579. public function get_items($start = 0, $end = 0)
  2580. {
  2581. if (!isset($this->data['items']))
  2582. {
  2583. if (!empty($this->multifeed_objects))
  2584. {
  2585. $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
  2586. }
  2587. else
  2588. {
  2589. $this->data['items'] = array();
  2590. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
  2591. {
  2592. $keys = array_keys($items);
  2593. foreach ($keys as $key)
  2594. {
  2595. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2596. }
  2597. }
  2598. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
  2599. {
  2600. $keys = array_keys($items);
  2601. foreach ($keys as $key)
  2602. {
  2603. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2604. }
  2605. }
  2606. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
  2607. {
  2608. $keys = array_keys($items);
  2609. foreach ($keys as $key)
  2610. {
  2611. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2612. }
  2613. }
  2614. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
  2615. {
  2616. $keys = array_keys($items);
  2617. foreach ($keys as $key)
  2618. {
  2619. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2620. }
  2621. }
  2622. if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
  2623. {
  2624. $keys = array_keys($items);
  2625. foreach ($keys as $key)
  2626. {
  2627. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2628. }
  2629. }
  2630. }
  2631. }
  2632. if (!empty($this->data['items']))
  2633. {
  2634. // If we want to order it by date, check if all items have a date, and then sort it
  2635. if ($this->order_by_date && empty($this->multifeed_objects))
  2636. {
  2637. if (!isset($this->data['ordered_items']))
  2638. {
  2639. $do_sort = true;
  2640. foreach ($this->data['items'] as $item)
  2641. {
  2642. if (!$item->get_date('U'))
  2643. {
  2644. $do_sort = false;
  2645. break;
  2646. }
  2647. }
  2648. $item = null;
  2649. $this->data['ordered_items'] = $this->data['items'];
  2650. if ($do_sort)
  2651. {
  2652. usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
  2653. }
  2654. }
  2655. $items = $this->data['ordered_items'];
  2656. }
  2657. else
  2658. {
  2659. $items = $this->data['items'];
  2660. }
  2661. // Slice the data as desired
  2662. if ($end === 0)
  2663. {
  2664. return array_slice($items, $start);
  2665. }
  2666. else
  2667. {
  2668. return array_slice($items, $start, $end);
  2669. }
  2670. }
  2671. else
  2672. {
  2673. return array();
  2674. }
  2675. }
  2676. /**
  2677. * Sorting callback for items
  2678. *
  2679. * @access private
  2680. * @param SimplePie $a
  2681. * @param SimplePie $b
  2682. * @return boolean
  2683. */
  2684. public static function sort_items($a, $b)
  2685. {
  2686. return $a->get_date('U') <= $b->get_date('U');
  2687. }
  2688. /**
  2689. * Merge items from several feeds into one
  2690. *
  2691. * If you're merging multiple feeds together, they need to all have dates
  2692. * for the items or else SimplePie will refuse to sort them.
  2693. *
  2694. * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
  2695. * @param array $urls List of SimplePie feed objects to merge
  2696. * @param int $start Starting item
  2697. * @param int $end Number of items to return
  2698. * @param int $limit Maximum number of items per feed
  2699. * @return array
  2700. */
  2701. public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
  2702. {
  2703. if (is_array($urls) && sizeof($urls) > 0)
  2704. {
  2705. $items = array();
  2706. foreach ($urls as $arg)
  2707. {
  2708. if ($arg instanceof SimplePie)
  2709. {
  2710. $items = array_merge($items, $arg->get_items(0, $limit));
  2711. }
  2712. else
  2713. {
  2714. trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
  2715. }
  2716. }
  2717. $do_sort = true;
  2718. foreach ($items as $item)
  2719. {
  2720. if (!$item->get_date('U'))
  2721. {
  2722. $do_sort = false;
  2723. break;
  2724. }
  2725. }
  2726. $item = null;
  2727. if ($do_sort)
  2728. {
  2729. usort($items, array(get_class($urls[0]), 'sort_items'));
  2730. }
  2731. if ($end === 0)
  2732. {
  2733. return array_slice($items, $start);
  2734. }
  2735. else
  2736. {
  2737. return array_slice($items, $start, $end);
  2738. }
  2739. }
  2740. else
  2741. {
  2742. trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
  2743. return array();
  2744. }
  2745. }
  2746. }
  2747. /**
  2748. * Manages `<media:copyright>` copyright tags as defined in Media RSS
  2749. *
  2750. * Used by {@see SimplePie_Enclosure::get_copyright()}
  2751. *
  2752. * This class can be overloaded with {@see SimplePie::set_copyright_class()}
  2753. *
  2754. * @package SimplePie
  2755. * @subpackage API
  2756. */
  2757. class SimplePie_Copyright
  2758. {
  2759. /**
  2760. * Copyright URL
  2761. *
  2762. * @var string
  2763. * @see get_url()
  2764. */
  2765. var $url;
  2766. /**
  2767. * Attribution
  2768. *
  2769. * @var string
  2770. * @see get_attribution()
  2771. */
  2772. var $label;
  2773. /**
  2774. * Constructor, used to input the data
  2775. *
  2776. * For documentation on all the parameters, see the corresponding
  2777. * properties and their accessors
  2778. */
  2779. public function __construct($url = null, $label = null)
  2780. {
  2781. $this->url = $url;
  2782. $this->label = $label;
  2783. }
  2784. /**
  2785. * String-ified version
  2786. *
  2787. * @return string
  2788. */
  2789. public function __toString()
  2790. {
  2791. // There is no $this->data here
  2792. return md5(serialize($this));
  2793. }
  2794. /**
  2795. * Get the copyright URL
  2796. *
  2797. * @return string|null URL to copyright information
  2798. */
  2799. public function get_url()
  2800. {
  2801. if ($this->url !== null)
  2802. {
  2803. return $this->url;
  2804. }
  2805. else
  2806. {
  2807. return null;
  2808. }
  2809. }
  2810. /**
  2811. * Get the attribution text
  2812. *
  2813. * @return string|null
  2814. */
  2815. public function get_attribution()
  2816. {
  2817. if ($this->label !== null)
  2818. {
  2819. return $this->label;
  2820. }
  2821. else
  2822. {
  2823. return null;
  2824. }
  2825. }
  2826. }
  2827. /**
  2828. * Used to create cache objects
  2829. *
  2830. * This class can be overloaded with {@see SimplePie::set_cache_class()},
  2831. * although the preferred way is to create your own handler
  2832. * via {@see register()}
  2833. *
  2834. * @package SimplePie
  2835. * @subpackage Caching
  2836. */
  2837. class SimplePie_Cache
  2838. {
  2839. /**
  2840. * Cache handler classes
  2841. *
  2842. * These receive 3 parameters to their constructor, as documented in
  2843. * {@see register()}
  2844. * @var array
  2845. */
  2846. protected static $handlers = array(
  2847. 'mysql' => 'SimplePie_Cache_MySQL',
  2848. 'memcache' => 'SimplePie_Cache_Memcache',
  2849. );
  2850. /**
  2851. * Don't call the constructor. Please.
  2852. */
  2853. private function __construct() { }
  2854. /**
  2855. * Create a new SimplePie_Cache object
  2856. *
  2857. * @param string $location URL location (scheme is used to determine handler)
  2858. * @param string $filename Unique identifier for cache object
  2859. * @param string $extension 'spi' or 'spc'
  2860. * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
  2861. */
  2862. public static function create($location, $filename, $extension)
  2863. {
  2864. $type = explode(':', $location, 2);
  2865. $type = $type[0];
  2866. if (!empty(self::$handlers[$type]))
  2867. {
  2868. $class = self::$handlers[$type];
  2869. return new $class($location, $filename, $extension);
  2870. }
  2871. return new SimplePie_Cache_File($location, $filename, $extension);
  2872. }
  2873. /**
  2874. * Register a handler
  2875. *
  2876. * @param string $type DSN type to register for
  2877. * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
  2878. */
  2879. public static function register($type, $class)
  2880. {
  2881. self::$handlers[$type] = $class;
  2882. }
  2883. /**
  2884. * Parse a URL into an array
  2885. *
  2886. * @param string $url
  2887. * @return array
  2888. */
  2889. public static function parse_URL($url)
  2890. {
  2891. $params = parse_url($url);
  2892. $params['extras'] = array();
  2893. if (isset($params['query']))
  2894. {
  2895. parse_str($params['query'], $params['extras']);
  2896. }
  2897. return $params;
  2898. }
  2899. }
  2900. /**
  2901. * Handles creating objects and calling methods
  2902. *
  2903. * Access this via {@see SimplePie::get_registry()}
  2904. *
  2905. * @package SimplePie
  2906. */
  2907. class SimplePie_Registry
  2908. {
  2909. /**
  2910. * Default class mapping
  2911. *
  2912. * Overriding classes *must* subclass these.
  2913. *
  2914. * @var array
  2915. */
  2916. protected $default = array(
  2917. 'Cache' => 'SimplePie_Cache',
  2918. 'Locator' => 'SimplePie_Locator',
  2919. 'Parser' => 'SimplePie_Parser',
  2920. 'File' => 'SimplePie_File',
  2921. 'Sanitize' => 'SimplePie_Sanitize',
  2922. 'Item' => 'SimplePie_Item',
  2923. 'Author' => 'SimplePie_Author',
  2924. 'Category' => 'SimplePie_Category',
  2925. 'Enclosure' => 'SimplePie_Enclosure',
  2926. 'Caption' => 'SimplePie_Caption',
  2927. 'Copyright' => 'SimplePie_Copyright',
  2928. 'Credit' => 'SimplePie_Credit',
  2929. 'Rating' => 'SimplePie_Rating',
  2930. 'Restriction' => 'SimplePie_Restriction',
  2931. 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
  2932. 'Source' => 'SimplePie_Source',
  2933. 'Misc' => 'SimplePie_Misc',
  2934. 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
  2935. 'Parse_Date' => 'SimplePie_Parse_Date',
  2936. );
  2937. /**
  2938. * Class mapping
  2939. *
  2940. * @see register()
  2941. * @var array
  2942. */
  2943. protected $classes = array();
  2944. /**
  2945. * Legacy classes
  2946. *
  2947. * @see register()
  2948. * @var array
  2949. */
  2950. protected $legacy = array();
  2951. /**
  2952. * Constructor
  2953. *
  2954. * No-op
  2955. */
  2956. public function __construct() { }
  2957. /**
  2958. * Register a class
  2959. *
  2960. * @param string $type See {@see $default} for names
  2961. * @param string $class Class name, must subclass the corresponding default
  2962. * @param bool $legacy Whether to enable legacy support for this class
  2963. * @return bool Successfulness
  2964. */
  2965. public function register($type, $class, $legacy = false)
  2966. {
  2967. if (!is_subclass_of($class, $this->default[$type]))
  2968. {
  2969. return false;
  2970. }
  2971. $this->classes[$type] = $class;
  2972. if ($legacy)
  2973. {
  2974. $this->legacy[] = $class;
  2975. }
  2976. return true;
  2977. }
  2978. /**
  2979. * Get the class registered for a type
  2980. *
  2981. * Where possible, use {@see create()} or {@see call()} instead
  2982. *
  2983. * @param string $type
  2984. * @return string|null
  2985. */
  2986. public function get_class($type)
  2987. {
  2988. if (!empty($this->classes[$type]))
  2989. {
  2990. return $this->classes[$type];
  2991. }
  2992. if (!empty($this->default[$type]))
  2993. {
  2994. return $this->default[$type];
  2995. }
  2996. return null;
  2997. }
  2998. /**
  2999. * Create a new instance of a given type
  3000. *
  3001. * @param string $type
  3002. * @param array $parameters Parameters to pass to the constructor
  3003. * @return object Instance of class
  3004. */
  3005. public function &create($type, $parameters = array())
  3006. {
  3007. $class = $this->get_class($type);
  3008. if (in_array($class, $this->legacy))
  3009. {
  3010. switch ($type)
  3011. {
  3012. case 'locator':
  3013. // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
  3014. // Specified: file, timeout, useragent, max_checked_feeds
  3015. $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
  3016. array_splice($parameters, 3, 1, $replacement);
  3017. break;
  3018. }
  3019. }
  3020. if (!method_exists($class, '__construct'))
  3021. {
  3022. $instance = new $class;
  3023. }
  3024. else
  3025. {
  3026. $reflector = new ReflectionClass($class);
  3027. $instance = $reflector->newInstanceArgs($parameters);
  3028. }
  3029. if (method_exists($instance, 'set_registry'))
  3030. {
  3031. $instance->set_registry($this);
  3032. }
  3033. return $instance;
  3034. }
  3035. /**
  3036. * Call a static method for a type
  3037. *
  3038. * @param string $type
  3039. * @param string $method
  3040. * @param array $parameters
  3041. * @return mixed
  3042. */
  3043. public function &call($type, $method, $parameters = array())
  3044. {
  3045. $class = $this->get_class($type);
  3046. $result = call_user_func_array(array($class, $method), $parameters);
  3047. return $result;
  3048. }
  3049. }
  3050. /**
  3051. * Base class for database-based caches
  3052. *
  3053. * @package SimplePie
  3054. * @subpackage Caching
  3055. */
  3056. abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
  3057. {
  3058. /**
  3059. * Helper for database conversion
  3060. *
  3061. * Converts a given {@see SimplePie} object into data to be stored
  3062. *
  3063. * @param SimplePie $data
  3064. * @return array First item is the serialized data for storage, second item is the unique ID for this item
  3065. */
  3066. protected static function prepare_simplepie_object_for_cache($data)
  3067. {
  3068. $items = $data->get_items();
  3069. $items_by_id = array();
  3070. if (!empty($items))
  3071. {
  3072. foreach ($items as $item)
  3073. {
  3074. $items_by_id[$item->get_id()] = $item;
  3075. }
  3076. if (count($items_by_id) !== count($items))
  3077. {
  3078. $items_by_id = array();
  3079. foreach ($items as $item)
  3080. {
  3081. $items_by_id[$item->get_id(true)] = $item;
  3082. }
  3083. }
  3084. if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
  3085. {
  3086. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
  3087. }
  3088. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
  3089. {
  3090. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
  3091. }
  3092. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
  3093. {
  3094. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
  3095. }
  3096. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
  3097. {
  3098. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
  3099. }
  3100. else
  3101. {
  3102. $channel = null;
  3103. }
  3104. if ($channel !== null)
  3105. {
  3106. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
  3107. {
  3108. unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
  3109. }
  3110. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
  3111. {
  3112. unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
  3113. }
  3114. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
  3115. {
  3116. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
  3117. }
  3118. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
  3119. {
  3120. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
  3121. }
  3122. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
  3123. {
  3124. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
  3125. }
  3126. }
  3127. if (isset($data->data['items']))
  3128. {
  3129. unset($data->data['items']);
  3130. }
  3131. if (isset($data->data['ordered_items']))
  3132. {
  3133. unset($data->data['ordered_items']);
  3134. }
  3135. }
  3136. return array(serialize($data->data), $items_by_id);
  3137. }
  3138. }
  3139. /**
  3140. * Caches data to the filesystem
  3141. *
  3142. * @package SimplePie
  3143. * @subpackage Caching
  3144. */
  3145. class SimplePie_Cache_File implements SimplePie_Cache_Base
  3146. {
  3147. /**
  3148. * Location string
  3149. *
  3150. * @see SimplePie::$cache_location
  3151. * @var string
  3152. */
  3153. protected $location;
  3154. /**
  3155. * Filename
  3156. *
  3157. * @var string
  3158. */
  3159. protected $filename;
  3160. /**
  3161. * File extension
  3162. *
  3163. * @var string
  3164. */
  3165. protected $extension;
  3166. /**
  3167. * File path
  3168. *
  3169. * @var string
  3170. */
  3171. protected $name;
  3172. /**
  3173. * Create a new cache object
  3174. *
  3175. * @param string $location Location string (from SimplePie::$cache_location)
  3176. * @param string $name Unique ID for the cache
  3177. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3178. */
  3179. public function __construct($location, $name, $type)
  3180. {
  3181. $this->location = $location;
  3182. $this->filename = $name;
  3183. $this->extension = $type;
  3184. $this->name = "$this->location/$this->filename.$this->extension";
  3185. }
  3186. /**
  3187. * Save data to the cache
  3188. *
  3189. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3190. * @return bool Successfulness
  3191. */
  3192. public function save($data)
  3193. {
  3194. if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
  3195. {
  3196. if ($data instanceof SimplePie)
  3197. {
  3198. $data = $data->data;
  3199. }
  3200. $data = serialize($data);
  3201. return (bool) file_put_contents($this->name, $data);
  3202. }
  3203. return false;
  3204. }
  3205. /**
  3206. * Retrieve the data saved to the cache
  3207. *
  3208. * @return array Data for SimplePie::$data
  3209. */
  3210. public function load()
  3211. {
  3212. if (file_exists($this->name) && is_readable($this->name))
  3213. {
  3214. return unserialize(file_get_contents($this->name));
  3215. }
  3216. return false;
  3217. }
  3218. /**
  3219. * Retrieve the last modified time for the cache
  3220. *
  3221. * @return int Timestamp
  3222. */
  3223. public function mtime()
  3224. {
  3225. if (file_exists($this->name))
  3226. {
  3227. return filemtime($this->name);
  3228. }
  3229. return false;
  3230. }
  3231. /**
  3232. * Set the last modified time to the current time
  3233. *
  3234. * @return bool Success status
  3235. */
  3236. public function touch()
  3237. {
  3238. if (file_exists($this->name))
  3239. {
  3240. return touch($this->name);
  3241. }
  3242. return false;
  3243. }
  3244. /**
  3245. * Remove the cache
  3246. *
  3247. * @return bool Success status
  3248. */
  3249. public function unlink()
  3250. {
  3251. if (file_exists($this->name))
  3252. {
  3253. return unlink($this->name);
  3254. }
  3255. return false;
  3256. }
  3257. }
  3258. /**
  3259. * Base for cache objects
  3260. *
  3261. * Classes to be used with {@see SimplePie_Cache::register()} are expected
  3262. * to implement this interface.
  3263. *
  3264. * @package SimplePie
  3265. * @subpackage Caching
  3266. */
  3267. interface SimplePie_Cache_Base
  3268. {
  3269. /**
  3270. * Feed cache type
  3271. *
  3272. * @var string
  3273. */
  3274. const TYPE_FEED = 'spc';
  3275. /**
  3276. * Image cache type
  3277. *
  3278. * @var string
  3279. */
  3280. const TYPE_IMAGE = 'spi';
  3281. /**
  3282. * Create a new cache object
  3283. *
  3284. * @param string $location Location string (from SimplePie::$cache_location)
  3285. * @param string $name Unique ID for the cache
  3286. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3287. */
  3288. public function __construct($location, $name, $type);
  3289. /**
  3290. * Save data to the cache
  3291. *
  3292. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3293. * @return bool Successfulness
  3294. */
  3295. public function save($data);
  3296. /**
  3297. * Retrieve the data saved to the cache
  3298. *
  3299. * @return array Data for SimplePie::$data
  3300. */
  3301. public function load();
  3302. /**
  3303. * Retrieve the last modified time for the cache
  3304. *
  3305. * @return int Timestamp
  3306. */
  3307. public function mtime();
  3308. /**
  3309. * Set the last modified time to the current time
  3310. *
  3311. * @return bool Success status
  3312. */
  3313. public function touch();
  3314. /**
  3315. * Remove the cache
  3316. *
  3317. * @return bool Success status
  3318. */
  3319. public function unlink();
  3320. }
  3321. /**
  3322. * Caches data to memcache
  3323. *
  3324. * Registered for URLs with the "memcache" protocol
  3325. *
  3326. * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
  3327. * connect to memcache on `localhost` on port 11211. All tables will be
  3328. * prefixed with `sp_` and data will expire after 3600 seconds
  3329. *
  3330. * @package SimplePie
  3331. * @subpackage Caching
  3332. * @uses Memcache
  3333. */
  3334. class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
  3335. {
  3336. /**
  3337. * Memcache instance
  3338. *
  3339. * @var Memcache
  3340. */
  3341. protected $cache;
  3342. /**
  3343. * Options
  3344. *
  3345. * @var array
  3346. */
  3347. protected $options;
  3348. /**
  3349. * Cache name
  3350. *
  3351. * @var string
  3352. */
  3353. protected $name;
  3354. /**
  3355. * Create a new cache object
  3356. *
  3357. * @param string $location Location string (from SimplePie::$cache_location)
  3358. * @param string $name Unique ID for the cache
  3359. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3360. */
  3361. public function __construct($location, $name, $type)
  3362. {
  3363. $this->options = array(
  3364. 'host' => '127.0.0.1',
  3365. 'port' => 11211,
  3366. 'extras' => array(
  3367. 'timeout' => 3600, // one hour
  3368. 'prefix' => 'simplepie_',
  3369. ),
  3370. );
  3371. $parsed = SimplePie_Cache::parse_URL($location);
  3372. $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
  3373. $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
  3374. $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
  3375. $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
  3376. $this->cache = new Memcache();
  3377. $this->cache->addServer($this->options['host'], (int) $this->options['port']);
  3378. }
  3379. /**
  3380. * Save data to the cache
  3381. *
  3382. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3383. * @return bool Successfulness
  3384. */
  3385. public function save($data)
  3386. {
  3387. if ($data instanceof SimplePie)
  3388. {
  3389. $data = $data->data;
  3390. }
  3391. return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
  3392. }
  3393. /**
  3394. * Retrieve the data saved to the cache
  3395. *
  3396. * @return array Data for SimplePie::$data
  3397. */
  3398. public function load()
  3399. {
  3400. $data = $this->cache->get($this->name);
  3401. if ($data !== false)
  3402. {
  3403. return unserialize($data);
  3404. }
  3405. return false;
  3406. }
  3407. /**
  3408. * Retrieve the last modified time for the cache
  3409. *
  3410. * @return int Timestamp
  3411. */
  3412. public function mtime()
  3413. {
  3414. $data = $this->cache->get($this->name);
  3415. if ($data !== false)
  3416. {
  3417. // essentially ignore the mtime because Memcache expires on it's own
  3418. return time();
  3419. }
  3420. return false;
  3421. }
  3422. /**
  3423. * Set the last modified time to the current time
  3424. *
  3425. * @return bool Success status
  3426. */
  3427. public function touch()
  3428. {
  3429. $data = $this->cache->get($this->name);
  3430. if ($data !== false)
  3431. {
  3432. return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
  3433. }
  3434. return false;
  3435. }
  3436. /**
  3437. * Remove the cache
  3438. *
  3439. * @return bool Success status
  3440. */
  3441. public function unlink()
  3442. {
  3443. return $this->cache->delete($this->name, 0);
  3444. }
  3445. }
  3446. /**
  3447. * Caches data to a MySQL database
  3448. *
  3449. * Registered for URLs with the "mysql" protocol
  3450. *
  3451. * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
  3452. * connect to the `mydb` database on `localhost` on port 3306, with the user
  3453. * `root` and the password `password`. All tables will be prefixed with `sp_`
  3454. *
  3455. * @package SimplePie
  3456. * @subpackage Caching
  3457. */
  3458. class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
  3459. {
  3460. /**
  3461. * PDO instance
  3462. *
  3463. * @var PDO
  3464. */
  3465. protected $mysql;
  3466. /**
  3467. * Options
  3468. *
  3469. * @var array
  3470. */
  3471. protected $options;
  3472. /**
  3473. * Cache ID
  3474. *
  3475. * @var string
  3476. */
  3477. protected $id;
  3478. /**
  3479. * Create a new cache object
  3480. *
  3481. * @param string $location Location string (from SimplePie::$cache_location)
  3482. * @param string $name Unique ID for the cache
  3483. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3484. */
  3485. public function __construct($location, $name, $type)
  3486. {
  3487. $this->options = array(
  3488. 'user' => null,
  3489. 'pass' => null,
  3490. 'host' => '127.0.0.1',
  3491. 'port' => '3306',
  3492. 'path' => '',
  3493. 'extras' => array(
  3494. 'prefix' => '',
  3495. ),
  3496. );
  3497. $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
  3498. // Path is prefixed with a "/"
  3499. $this->options['dbname'] = substr($this->options['path'], 1);
  3500. try
  3501. {
  3502. $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
  3503. }
  3504. catch (PDOException $e)
  3505. {
  3506. $this->mysql = null;
  3507. return;
  3508. }
  3509. $this->id = $name . $type;
  3510. if (!$query = $this->mysql->query('SHOW TABLES'))
  3511. {
  3512. $this->mysql = null;
  3513. return;
  3514. }
  3515. $db = array();
  3516. while ($row = $query->fetchColumn())
  3517. {
  3518. $db[] = $row;
  3519. }
  3520. if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
  3521. {
  3522. $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
  3523. if ($query === false)
  3524. {
  3525. $this->mysql = null;
  3526. }
  3527. }
  3528. if (!in_array($this->options['extras']['prefix'] . 'items', $db))
  3529. {
  3530. $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
  3531. if ($query === false)
  3532. {
  3533. $this->mysql = null;
  3534. }
  3535. }
  3536. }
  3537. /**
  3538. * Save data to the cache
  3539. *
  3540. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3541. * @return bool Successfulness
  3542. */
  3543. public function save($data)
  3544. {
  3545. if ($this->mysql === null)
  3546. {
  3547. return false;
  3548. }
  3549. if ($data instanceof SimplePie)
  3550. {
  3551. $data = clone $data;
  3552. $prepared = self::prepare_simplepie_object_for_cache($data);
  3553. $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
  3554. $query->bindValue(':feed', $this->id);
  3555. if ($query->execute())
  3556. {
  3557. if ($query->fetchColumn() > 0)
  3558. {
  3559. $items = count($prepared[1]);
  3560. if ($items)
  3561. {
  3562. $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
  3563. $query = $this->mysql->prepare($sql);
  3564. $query->bindValue(':items', $items);
  3565. }
  3566. else
  3567. {
  3568. $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
  3569. $query = $this->mysql->prepare($sql);
  3570. }
  3571. $query->bindValue(':data', $prepared[0]);
  3572. $query->bindValue(':time', time());
  3573. $query->bindValue(':feed', $this->id);
  3574. if (!$query->execute())
  3575. {
  3576. return false;
  3577. }
  3578. }
  3579. else
  3580. {
  3581. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
  3582. $query->bindValue(':feed', $this->id);
  3583. $query->bindValue(':count', count($prepared[1]));
  3584. $query->bindValue(':data', $prepared[0]);
  3585. $query->bindValue(':time', time());
  3586. if (!$query->execute())
  3587. {
  3588. return false;
  3589. }
  3590. }
  3591. $ids = array_keys($prepared[1]);
  3592. if (!empty($ids))
  3593. {
  3594. foreach ($ids as $id)
  3595. {
  3596. $database_ids[] = $this->mysql->quote($id);
  3597. }
  3598. $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
  3599. $query->bindValue(':feed', $this->id);
  3600. if ($query->execute())
  3601. {
  3602. $existing_ids = array();
  3603. while ($row = $query->fetchColumn())
  3604. {
  3605. $existing_ids[] = $row;
  3606. }
  3607. $new_ids = array_diff($ids, $existing_ids);
  3608. foreach ($new_ids as $new_id)
  3609. {
  3610. if (!($date = $prepared[1][$new_id]->get_date('U')))
  3611. {
  3612. $date = time();
  3613. }
  3614. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
  3615. $query->bindValue(':feed', $this->id);
  3616. $query->bindValue(':id', $new_id);
  3617. $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
  3618. $query->bindValue(':date', $date);
  3619. if (!$query->execute())
  3620. {
  3621. return false;
  3622. }
  3623. }
  3624. return true;
  3625. }
  3626. }
  3627. else
  3628. {
  3629. return true;
  3630. }
  3631. }
  3632. }
  3633. else
  3634. {
  3635. $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
  3636. $query->bindValue(':feed', $this->id);
  3637. if ($query->execute())
  3638. {
  3639. if ($query->rowCount() > 0)
  3640. {
  3641. $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
  3642. $query->bindValue(':data', serialize($data));
  3643. $query->bindValue(':time', time());
  3644. $query->bindValue(':feed', $this->id);
  3645. if ($this->execute())
  3646. {
  3647. return true;
  3648. }
  3649. }
  3650. else
  3651. {
  3652. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
  3653. $query->bindValue(':id', $this->id);
  3654. $query->bindValue(':data', serialize($data));
  3655. $query->bindValue(':time', time());
  3656. if ($query->execute())
  3657. {
  3658. return true;
  3659. }
  3660. }
  3661. }
  3662. }
  3663. return false;
  3664. }
  3665. /**
  3666. * Retrieve the data saved to the cache
  3667. *
  3668. * @return array Data for SimplePie::$data
  3669. */
  3670. public function load()
  3671. {
  3672. if ($this->mysql === null)
  3673. {
  3674. return false;
  3675. }
  3676. $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3677. $query->bindValue(':id', $this->id);
  3678. if ($query->execute() && ($row = $query->fetch()))
  3679. {
  3680. $data = unserialize($row[1]);
  3681. if (isset($this->options['items'][0]))
  3682. {
  3683. $items = (int) $this->options['items'][0];
  3684. }
  3685. else
  3686. {
  3687. $items = (int) $row[0];
  3688. }
  3689. if ($items !== 0)
  3690. {
  3691. if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
  3692. {
  3693. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
  3694. }
  3695. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
  3696. {
  3697. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
  3698. }
  3699. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
  3700. {
  3701. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
  3702. }
  3703. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
  3704. {
  3705. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
  3706. }
  3707. else
  3708. {
  3709. $feed = null;
  3710. }
  3711. if ($feed !== null)
  3712. {
  3713. $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
  3714. if ($items > 0)
  3715. {
  3716. $sql .= ' LIMIT ' . $items;
  3717. }
  3718. $query = $this->mysql->prepare($sql);
  3719. $query->bindValue(':feed', $this->id);
  3720. if ($query->execute())
  3721. {
  3722. while ($row = $query->fetchColumn())
  3723. {
  3724. $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
  3725. }
  3726. }
  3727. else
  3728. {
  3729. return false;
  3730. }
  3731. }
  3732. }
  3733. return $data;
  3734. }
  3735. return false;
  3736. }
  3737. /**
  3738. * Retrieve the last modified time for the cache
  3739. *
  3740. * @return int Timestamp
  3741. */
  3742. public function mtime()
  3743. {
  3744. if ($this->mysql === null)
  3745. {
  3746. return false;
  3747. }
  3748. $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3749. $query->bindValue(':id', $this->id);
  3750. if ($query->execute() && ($time = $query->fetchColumn()))
  3751. {
  3752. return $time;
  3753. }
  3754. else
  3755. {
  3756. return false;
  3757. }
  3758. }
  3759. /**
  3760. * Set the last modified time to the current time
  3761. *
  3762. * @return bool Success status
  3763. */
  3764. public function touch()
  3765. {
  3766. if ($this->mysql === null)
  3767. {
  3768. return false;
  3769. }
  3770. $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
  3771. $query->bindValue(':time', time());
  3772. $query->bindValue(':id', $this->id);
  3773. if ($query->execute() && $query->rowCount() > 0)
  3774. {
  3775. return true;
  3776. }
  3777. else
  3778. {
  3779. return false;
  3780. }
  3781. }
  3782. /**
  3783. * Remove the cache
  3784. *
  3785. * @return bool Success status
  3786. */
  3787. public function unlink()
  3788. {
  3789. if ($this->mysql === null)
  3790. {
  3791. return false;
  3792. }
  3793. $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3794. $query->bindValue(':id', $this->id);
  3795. $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
  3796. $query2->bindValue(':id', $this->id);
  3797. if ($query->execute() && $query2->execute())
  3798. {
  3799. return true;
  3800. }
  3801. else
  3802. {
  3803. return false;
  3804. }
  3805. }
  3806. }
  3807. /**
  3808. * Used for data cleanup and post-processing
  3809. *
  3810. *
  3811. * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
  3812. *
  3813. * @package SimplePie
  3814. * @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
  3815. */
  3816. class SimplePie_Sanitize
  3817. {
  3818. // Private vars
  3819. var $base;
  3820. // Options
  3821. var $remove_div = true;
  3822. var $image_handler = '';
  3823. var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
  3824. var $encode_instead_of_strip = false;
  3825. var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
  3826. var $strip_comments = false;
  3827. var $output_encoding = 'UTF-8';
  3828. var $enable_cache = true;
  3829. var $cache_location = './cache';
  3830. var $cache_name_function = 'md5';
  3831. var $timeout = 10;
  3832. var $useragent = '';
  3833. var $force_fsockopen = false;
  3834. var $replace_url_attributes = null;
  3835. public function __construct()
  3836. {
  3837. // Set defaults
  3838. $this->set_url_replacements(null);
  3839. }
  3840. public function remove_div($enable = true)
  3841. {
  3842. $this->remove_div = (bool) $enable;
  3843. }
  3844. public function set_image_handler($page = false)
  3845. {
  3846. if ($page)
  3847. {
  3848. $this->image_handler = (string) $page;
  3849. }
  3850. else
  3851. {
  3852. $this->image_handler = false;
  3853. }
  3854. }
  3855. public function set_registry(SimplePie_Registry $registry)
  3856. {
  3857. $this->registry = $registry;
  3858. }
  3859. public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
  3860. {
  3861. if (isset($enable_cache))
  3862. {
  3863. $this->enable_cache = (bool) $enable_cache;
  3864. }
  3865. if ($cache_location)
  3866. {
  3867. $this->cache_location = (string) $cache_location;
  3868. }
  3869. if ($cache_name_function)
  3870. {
  3871. $this->cache_name_function = (string) $cache_name_function;
  3872. }
  3873. }
  3874. public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
  3875. {
  3876. if ($timeout)
  3877. {
  3878. $this->timeout = (string) $timeout;
  3879. }
  3880. if ($useragent)
  3881. {
  3882. $this->useragent = (string) $useragent;
  3883. }
  3884. if ($force_fsockopen)
  3885. {
  3886. $this->force_fsockopen = (string) $force_fsockopen;
  3887. }
  3888. }
  3889. public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
  3890. {
  3891. if ($tags)
  3892. {
  3893. if (is_array($tags))
  3894. {
  3895. $this->strip_htmltags = $tags;
  3896. }
  3897. else
  3898. {
  3899. $this->strip_htmltags = explode(',', $tags);
  3900. }
  3901. }
  3902. else
  3903. {
  3904. $this->strip_htmltags = false;
  3905. }
  3906. }
  3907. public function encode_instead_of_strip($encode = false)
  3908. {
  3909. $this->encode_instead_of_strip = (bool) $encode;
  3910. }
  3911. public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
  3912. {
  3913. if ($attribs)
  3914. {
  3915. if (is_array($attribs))
  3916. {
  3917. $this->strip_attributes = $attribs;
  3918. }
  3919. else
  3920. {
  3921. $this->strip_attributes = explode(',', $attribs);
  3922. }
  3923. }
  3924. else
  3925. {
  3926. $this->strip_attributes = false;
  3927. }
  3928. }
  3929. public function strip_comments($strip = false)
  3930. {
  3931. $this->strip_comments = (bool) $strip;
  3932. }
  3933. public function set_output_encoding($encoding = 'UTF-8')
  3934. {
  3935. $this->output_encoding = (string) $encoding;
  3936. }
  3937. /**
  3938. * Set element/attribute key/value pairs of HTML attributes
  3939. * containing URLs that need to be resolved relative to the feed
  3940. *
  3941. * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
  3942. * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
  3943. * |q|@cite
  3944. *
  3945. * @since 1.0
  3946. * @param array|null $element_attribute Element/attribute key/value pairs, null for default
  3947. */
  3948. public function set_url_replacements($element_attribute = null)
  3949. {
  3950. if ($element_attribute === null)
  3951. {
  3952. $element_attribute = array(
  3953. 'a' => 'href',
  3954. 'area' => 'href',
  3955. 'blockquote' => 'cite',
  3956. 'del' => 'cite',
  3957. 'form' => 'action',
  3958. 'img' => array(
  3959. 'longdesc',
  3960. 'src'
  3961. ),
  3962. 'input' => 'src',
  3963. 'ins' => 'cite',
  3964. 'q' => 'cite'
  3965. );
  3966. }
  3967. $this->replace_url_attributes = (array) $element_attribute;
  3968. }
  3969. public function sanitize($data, $type, $base = '')
  3970. {
  3971. $data = trim($data);
  3972. if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
  3973. {
  3974. if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
  3975. {
  3976. if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
  3977. {
  3978. $type |= SIMPLEPIE_CONSTRUCT_HTML;
  3979. }
  3980. else
  3981. {
  3982. $type |= SIMPLEPIE_CONSTRUCT_TEXT;
  3983. }
  3984. }
  3985. if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
  3986. {
  3987. $data = base64_decode($data);
  3988. }
  3989. if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
  3990. {
  3991. $document = new DOMDocument();
  3992. $document->encoding = 'UTF-8';
  3993. $data = $this->preprocess($data, $type);
  3994. set_error_handler(array('SimplePie_Misc', 'silence_errors'));
  3995. $document->loadHTML($data);
  3996. restore_error_handler();
  3997. // Strip comments
  3998. if ($this->strip_comments)
  3999. {
  4000. $xpath = new DOMXPath($document);
  4001. $comments = $xpath->query('//comment()');
  4002. foreach ($comments as $comment)
  4003. {
  4004. $comment->parentNode->removeChild($comment);
  4005. }
  4006. }
  4007. // Strip out HTML tags and attributes that might cause various security problems.
  4008. // Based on recommendations by Mark Pilgrim at:
  4009. // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
  4010. if ($this->strip_htmltags)
  4011. {
  4012. foreach ($this->strip_htmltags as $tag)
  4013. {
  4014. $this->strip_tag($tag, $document, $type);
  4015. }
  4016. }
  4017. if ($this->strip_attributes)
  4018. {
  4019. foreach ($this->strip_attributes as $attrib)
  4020. {
  4021. $this->strip_attr($attrib, $document);
  4022. }
  4023. }
  4024. // Replace relative URLs
  4025. $this->base = $base;
  4026. foreach ($this->replace_url_attributes as $element => $attributes)
  4027. {
  4028. $this->replace_urls($document, $element, $attributes);
  4029. }
  4030. // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
  4031. if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
  4032. {
  4033. $images = $document->getElementsByTagName('img');
  4034. foreach ($images as $img)
  4035. {
  4036. if ($img->hasAttribute('src'))
  4037. {
  4038. $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
  4039. $cache = $this->registry->call('Cache', 'create', array($this->cache_location, $image_url, 'spi'));
  4040. if ($cache->load())
  4041. {
  4042. $img->setAttribute('src', $this->image_handler . $image_url);
  4043. }
  4044. else
  4045. {
  4046. $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
  4047. $headers = $file->headers;
  4048. if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
  4049. {
  4050. if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
  4051. {
  4052. $img->setAttribute('src', $this->image_handler . $image_url);
  4053. }
  4054. else
  4055. {
  4056. trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
  4057. }
  4058. }
  4059. }
  4060. }
  4061. }
  4062. }
  4063. // Remove the DOCTYPE
  4064. // Seems to cause segfaulting if we don't do this
  4065. if ($document->firstChild instanceof DOMDocumentType)
  4066. {
  4067. $document->removeChild($document->firstChild);
  4068. }
  4069. // Move everything from the body to the root
  4070. $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
  4071. $document->replaceChild($real_body, $document->firstChild);
  4072. // Finally, convert to a HTML string
  4073. $data = trim($document->saveHTML());
  4074. if ($this->remove_div)
  4075. {
  4076. $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
  4077. $data = preg_replace('/<\/div>$/', '', $data);
  4078. }
  4079. else
  4080. {
  4081. $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
  4082. }
  4083. }
  4084. if ($type & SIMPLEPIE_CONSTRUCT_IRI)
  4085. {
  4086. $data = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
  4087. }
  4088. if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
  4089. {
  4090. $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
  4091. }
  4092. if ($this->output_encoding !== 'UTF-8')
  4093. {
  4094. $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
  4095. }
  4096. }
  4097. return $data;
  4098. }
  4099. protected function preprocess($html, $type)
  4100. {
  4101. $ret = '';
  4102. if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
  4103. {
  4104. // Atom XHTML constructs are wrapped with a div by default
  4105. // Note: No protection if $html contains a stray </div>!
  4106. $html = '<div>' . $html . '</div>';
  4107. $ret .= '<!DOCTYPE html>';
  4108. $content_type = 'text/html';
  4109. }
  4110. else
  4111. {
  4112. $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
  4113. $content_type = 'application/xhtml+xml';
  4114. }
  4115. $ret .= '<html><head>';
  4116. $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
  4117. $ret .= '</head><body>' . $html . '</body></html>';
  4118. return $ret;
  4119. }
  4120. public function replace_urls($document, $tag, $attributes)
  4121. {
  4122. if (!is_array($attributes))
  4123. {
  4124. $attributes = array($attributes);
  4125. }
  4126. if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
  4127. {
  4128. $elements = $document->getElementsByTagName($tag);
  4129. foreach ($elements as $element)
  4130. {
  4131. foreach ($attributes as $attribute)
  4132. {
  4133. if ($element->hasAttribute($attribute))
  4134. {
  4135. $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
  4136. $element->setAttribute($attribute, $value);
  4137. }
  4138. }
  4139. }
  4140. }
  4141. }
  4142. public function do_strip_htmltags($match)
  4143. {
  4144. if ($this->encode_instead_of_strip)
  4145. {
  4146. if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
  4147. {
  4148. $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
  4149. $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
  4150. return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
  4151. }
  4152. else
  4153. {
  4154. return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
  4155. }
  4156. }
  4157. elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
  4158. {
  4159. return $match[4];
  4160. }
  4161. else
  4162. {
  4163. return '';
  4164. }
  4165. }
  4166. protected function strip_tag($tag, $document, $type)
  4167. {
  4168. $xpath = new DOMXPath($document);
  4169. $elements = $xpath->query('body//' . $tag);
  4170. if ($this->encode_instead_of_strip)
  4171. {
  4172. foreach ($elements as $element)
  4173. {
  4174. $fragment = $document->createDocumentFragment();
  4175. // For elements which aren't script or style, include the tag itself
  4176. if (!in_array($tag, array('script', 'style')))
  4177. {
  4178. $text = '<' . $tag;
  4179. if ($element->hasAttributes())
  4180. {
  4181. $attrs = array();
  4182. foreach ($element->attributes as $name => $attr)
  4183. {
  4184. $value = $attr->value;
  4185. // In XHTML, empty values should never exist, so we repeat the value
  4186. if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
  4187. {
  4188. $value = $name;
  4189. }
  4190. // For HTML, empty is fine
  4191. elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
  4192. {
  4193. $attrs[] = $name;
  4194. continue;
  4195. }
  4196. // Standard attribute text
  4197. $attrs[] = $name . '="' . $attr->value . '"';
  4198. }
  4199. $text .= ' ' . implode(' ', $attrs);
  4200. }
  4201. $text .= '>';
  4202. $fragment->appendChild(new DOMText($text));
  4203. }
  4204. $number = $element->childNodes->length;
  4205. for ($i = $number; $i > 0; $i--)
  4206. {
  4207. $child = $element->childNodes->item(0);
  4208. $fragment->appendChild($child);
  4209. }
  4210. if (!in_array($tag, array('script', 'style')))
  4211. {
  4212. $fragment->appendChild(new DOMText('</' . $tag . '>'));
  4213. }
  4214. $element->parentNode->replaceChild($fragment, $element);
  4215. }
  4216. return;
  4217. }
  4218. elseif (in_array($tag, array('script', 'style')))
  4219. {
  4220. foreach ($elements as $element)
  4221. {
  4222. $element->parentNode->removeChild($element);
  4223. }
  4224. return;
  4225. }
  4226. else
  4227. {
  4228. foreach ($elements as $element)
  4229. {
  4230. $fragment = $document->createDocumentFragment();
  4231. $number = $element->childNodes->length;
  4232. for ($i = $number; $i > 0; $i--)
  4233. {
  4234. $child = $element->childNodes->item(0);
  4235. $fragment->appendChild($child);
  4236. }
  4237. $element->parentNode->replaceChild($fragment, $element);
  4238. }
  4239. }
  4240. }
  4241. protected function strip_attr($attrib, $document)
  4242. {
  4243. $xpath = new DOMXPath($document);
  4244. $elements = $xpath->query('//*[@' . $attrib . ']');
  4245. foreach ($elements as $element)
  4246. {
  4247. $element->removeAttribute($attrib);
  4248. }
  4249. }
  4250. }
  4251. /**
  4252. * Handles everything related to enclosures (including Media RSS and iTunes RSS)
  4253. *
  4254. * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
  4255. *
  4256. * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
  4257. *
  4258. * @package SimplePie
  4259. * @subpackage API
  4260. */
  4261. class SimplePie_Enclosure
  4262. {
  4263. /**
  4264. * @var string
  4265. * @see get_bitrate()
  4266. */
  4267. var $bitrate;
  4268. /**
  4269. * @var array
  4270. * @see get_captions()
  4271. */
  4272. var $captions;
  4273. /**
  4274. * @var array
  4275. * @see get_categories()
  4276. */
  4277. var $categories;
  4278. /**
  4279. * @var int
  4280. * @see get_channels()
  4281. */
  4282. var $channels;
  4283. /**
  4284. * @var SimplePie_Copyright
  4285. * @see get_copyright()
  4286. */
  4287. var $copyright;
  4288. /**
  4289. * @var array
  4290. * @see get_credits()
  4291. */
  4292. var $credits;
  4293. /**
  4294. * @var string
  4295. * @see get_description()
  4296. */
  4297. var $description;
  4298. /**
  4299. * @var int
  4300. * @see get_duration()
  4301. */
  4302. var $duration;
  4303. /**
  4304. * @var string
  4305. * @see get_expression()
  4306. */
  4307. var $expression;
  4308. /**
  4309. * @var string
  4310. * @see get_framerate()
  4311. */
  4312. var $framerate;
  4313. /**
  4314. * @var string
  4315. * @see get_handler()
  4316. */
  4317. var $handler;
  4318. /**
  4319. * @var array
  4320. * @see get_hashes()
  4321. */
  4322. var $hashes;
  4323. /**
  4324. * @var string
  4325. * @see get_height()
  4326. */
  4327. var $height;
  4328. /**
  4329. * @deprecated
  4330. * @var null
  4331. */
  4332. var $javascript;
  4333. /**
  4334. * @var array
  4335. * @see get_keywords()
  4336. */
  4337. var $keywords;
  4338. /**
  4339. * @var string
  4340. * @see get_language()
  4341. */
  4342. var $lang;
  4343. /**
  4344. * @var string
  4345. * @see get_length()
  4346. */
  4347. var $length;
  4348. /**
  4349. * @var string
  4350. * @see get_link()
  4351. */
  4352. var $link;
  4353. /**
  4354. * @var string
  4355. * @see get_medium()
  4356. */
  4357. var $medium;
  4358. /**
  4359. * @var string
  4360. * @see get_player()
  4361. */
  4362. var $player;
  4363. /**
  4364. * @var array
  4365. * @see get_ratings()
  4366. */
  4367. var $ratings;
  4368. /**
  4369. * @var array
  4370. * @see get_restrictions()
  4371. */
  4372. var $restrictions;
  4373. /**
  4374. * @var string
  4375. * @see get_sampling_rate()
  4376. */
  4377. var $samplingrate;
  4378. /**
  4379. * @var array
  4380. * @see get_thumbnails()
  4381. */
  4382. var $thumbnails;
  4383. /**
  4384. * @var string
  4385. * @see get_title()
  4386. */
  4387. var $title;
  4388. /**
  4389. * @var string
  4390. * @see get_type()
  4391. */
  4392. var $type;
  4393. /**
  4394. * @var string
  4395. * @see get_width()
  4396. */
  4397. var $width;
  4398. /**
  4399. * Constructor, used to input the data
  4400. *
  4401. * For documentation on all the parameters, see the corresponding
  4402. * properties and their accessors
  4403. *
  4404. * @uses idna_convert If available, this will convert an IDN
  4405. */
  4406. public function __construct($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
  4407. {
  4408. $this->bitrate = $bitrate;
  4409. $this->captions = $captions;
  4410. $this->categories = $categories;
  4411. $this->channels = $channels;
  4412. $this->copyright = $copyright;
  4413. $this->credits = $credits;
  4414. $this->description = $description;
  4415. $this->duration = $duration;
  4416. $this->expression = $expression;
  4417. $this->framerate = $framerate;
  4418. $this->hashes = $hashes;
  4419. $this->height = $height;
  4420. $this->keywords = $keywords;
  4421. $this->lang = $lang;
  4422. $this->length = $length;
  4423. $this->link = $link;
  4424. $this->medium = $medium;
  4425. $this->player = $player;
  4426. $this->ratings = $ratings;
  4427. $this->restrictions = $restrictions;
  4428. $this->samplingrate = $samplingrate;
  4429. $this->thumbnails = $thumbnails;
  4430. $this->title = $title;
  4431. $this->type = $type;
  4432. $this->width = $width;
  4433. if (class_exists('idna_convert'))
  4434. {
  4435. $idn = new idna_convert();
  4436. $parsed = SimplePie_Misc::parse_url($link);
  4437. $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
  4438. }
  4439. $this->handler = $this->get_handler(); // Needs to load last
  4440. }
  4441. /**
  4442. * String-ified version
  4443. *
  4444. * @return string
  4445. */
  4446. public function __toString()
  4447. {
  4448. // There is no $this->data here
  4449. return md5(serialize($this));
  4450. }
  4451. /**
  4452. * Get the bitrate
  4453. *
  4454. * @return string|null
  4455. */
  4456. public function get_bitrate()
  4457. {
  4458. if ($this->bitrate !== null)
  4459. {
  4460. return $this->bitrate;
  4461. }
  4462. else
  4463. {
  4464. return null;
  4465. }
  4466. }
  4467. /**
  4468. * Get a single caption
  4469. *
  4470. * @param int $key
  4471. * @return SimplePie_Caption|null
  4472. */
  4473. public function get_caption($key = 0)
  4474. {
  4475. $captions = $this->get_captions();
  4476. if (isset($captions[$key]))
  4477. {
  4478. return $captions[$key];
  4479. }
  4480. else
  4481. {
  4482. return null;
  4483. }
  4484. }
  4485. /**
  4486. * Get all captions
  4487. *
  4488. * @return array|null Array of {@see SimplePie_Caption} objects
  4489. */
  4490. public function get_captions()
  4491. {
  4492. if ($this->captions !== null)
  4493. {
  4494. return $this->captions;
  4495. }
  4496. else
  4497. {
  4498. return null;
  4499. }
  4500. }
  4501. /**
  4502. * Get a single category
  4503. *
  4504. * @param int $key
  4505. * @return SimplePie_Category|null
  4506. */
  4507. public function get_category($key = 0)
  4508. {
  4509. $categories = $this->get_categories();
  4510. if (isset($categories[$key]))
  4511. {
  4512. return $categories[$key];
  4513. }
  4514. else
  4515. {
  4516. return null;
  4517. }
  4518. }
  4519. /**
  4520. * Get all categories
  4521. *
  4522. * @return array|null Array of {@see SimplePie_Category} objects
  4523. */
  4524. public function get_categories()
  4525. {
  4526. if ($this->categories !== null)
  4527. {
  4528. return $this->categories;
  4529. }
  4530. else
  4531. {
  4532. return null;
  4533. }
  4534. }
  4535. /**
  4536. * Get the number of audio channels
  4537. *
  4538. * @return int|null
  4539. */
  4540. public function get_channels()
  4541. {
  4542. if ($this->channels !== null)
  4543. {
  4544. return $this->channels;
  4545. }
  4546. else
  4547. {
  4548. return null;
  4549. }
  4550. }
  4551. /**
  4552. * Get the copyright information
  4553. *
  4554. * @return SimplePie_Copyright|null
  4555. */
  4556. public function get_copyright()
  4557. {
  4558. if ($this->copyright !== null)
  4559. {
  4560. return $this->copyright;
  4561. }
  4562. else
  4563. {
  4564. return null;
  4565. }
  4566. }
  4567. /**
  4568. * Get a single credit
  4569. *
  4570. * @param int $key
  4571. * @return SimplePie_Credit|null
  4572. */
  4573. public function get_credit($key = 0)
  4574. {
  4575. $credits = $this->get_credits();
  4576. if (isset($credits[$key]))
  4577. {
  4578. return $credits[$key];
  4579. }
  4580. else
  4581. {
  4582. return null;
  4583. }
  4584. }
  4585. /**
  4586. * Get all credits
  4587. *
  4588. * @return array|null Array of {@see SimplePie_Credit} objects
  4589. */
  4590. public function get_credits()
  4591. {
  4592. if ($this->credits !== null)
  4593. {
  4594. return $this->credits;
  4595. }
  4596. else
  4597. {
  4598. return null;
  4599. }
  4600. }
  4601. /**
  4602. * Get the description of the enclosure
  4603. *
  4604. * @return string|null
  4605. */
  4606. public function get_description()
  4607. {
  4608. if ($this->description !== null)
  4609. {
  4610. return $this->description;
  4611. }
  4612. else
  4613. {
  4614. return null;
  4615. }
  4616. }
  4617. /**
  4618. * Get the duration of the enclosure
  4619. *
  4620. * @param string $convert Convert seconds into hh:mm:ss
  4621. * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
  4622. */
  4623. public function get_duration($convert = false)
  4624. {
  4625. if ($this->duration !== null)
  4626. {
  4627. if ($convert)
  4628. {
  4629. $time = SimplePie_Misc::time_hms($this->duration);
  4630. return $time;
  4631. }
  4632. else
  4633. {
  4634. return $this->duration;
  4635. }
  4636. }
  4637. else
  4638. {
  4639. return null;
  4640. }
  4641. }
  4642. /**
  4643. * Get the expression
  4644. *
  4645. * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
  4646. */
  4647. public function get_expression()
  4648. {
  4649. if ($this->expression !== null)
  4650. {
  4651. return $this->expression;
  4652. }
  4653. else
  4654. {
  4655. return 'full';
  4656. }
  4657. }
  4658. /**
  4659. * Get the file extension
  4660. *
  4661. * @return string|null
  4662. */
  4663. public function get_extension()
  4664. {
  4665. if ($this->link !== null)
  4666. {
  4667. $url = SimplePie_Misc::parse_url($this->link);
  4668. if ($url['path'] !== '')
  4669. {
  4670. return pathinfo($url['path'], PATHINFO_EXTENSION);
  4671. }
  4672. }
  4673. return null;
  4674. }
  4675. /**
  4676. * Get the framerate (in frames-per-second)
  4677. *
  4678. * @return string|null
  4679. */
  4680. public function get_framerate()
  4681. {
  4682. if ($this->framerate !== null)
  4683. {
  4684. return $this->framerate;
  4685. }
  4686. else
  4687. {
  4688. return null;
  4689. }
  4690. }
  4691. /**
  4692. * Get the preferred handler
  4693. *
  4694. * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
  4695. */
  4696. public function get_handler()
  4697. {
  4698. return $this->get_real_type(true);
  4699. }
  4700. /**
  4701. * Get a single hash
  4702. *
  4703. * @link http://www.rssboard.org/media-rss#media-hash
  4704. * @param int $key
  4705. * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
  4706. */
  4707. public function get_hash($key = 0)
  4708. {
  4709. $hashes = $this->get_hashes();
  4710. if (isset($hashes[$key]))
  4711. {
  4712. return $hashes[$key];
  4713. }
  4714. else
  4715. {
  4716. return null;
  4717. }
  4718. }
  4719. /**
  4720. * Get all credits
  4721. *
  4722. * @return array|null Array of strings, see {@see get_hash()}
  4723. */
  4724. public function get_hashes()
  4725. {
  4726. if ($this->hashes !== null)
  4727. {
  4728. return $this->hashes;
  4729. }
  4730. else
  4731. {
  4732. return null;
  4733. }
  4734. }
  4735. /**
  4736. * Get the height
  4737. *
  4738. * @return string|null
  4739. */
  4740. public function get_height()
  4741. {
  4742. if ($this->height !== null)
  4743. {
  4744. return $this->height;
  4745. }
  4746. else
  4747. {
  4748. return null;
  4749. }
  4750. }
  4751. /**
  4752. * Get the language
  4753. *
  4754. * @link http://tools.ietf.org/html/rfc3066
  4755. * @return string|null Language code as per RFC 3066
  4756. */
  4757. public function get_language()
  4758. {
  4759. if ($this->lang !== null)
  4760. {
  4761. return $this->lang;
  4762. }
  4763. else
  4764. {
  4765. return null;
  4766. }
  4767. }
  4768. /**
  4769. * Get a single keyword
  4770. *
  4771. * @param int $key
  4772. * @return string|null
  4773. */
  4774. public function get_keyword($key = 0)
  4775. {
  4776. $keywords = $this->get_keywords();
  4777. if (isset($keywords[$key]))
  4778. {
  4779. return $keywords[$key];
  4780. }
  4781. else
  4782. {
  4783. return null;
  4784. }
  4785. }
  4786. /**
  4787. * Get all keywords
  4788. *
  4789. * @return array|null Array of strings
  4790. */
  4791. public function get_keywords()
  4792. {
  4793. if ($this->keywords !== null)
  4794. {
  4795. return $this->keywords;
  4796. }
  4797. else
  4798. {
  4799. return null;
  4800. }
  4801. }
  4802. /**
  4803. * Get length
  4804. *
  4805. * @return float Length in bytes
  4806. */
  4807. public function get_length()
  4808. {
  4809. if ($this->length !== null)
  4810. {
  4811. return $this->length;
  4812. }
  4813. else
  4814. {
  4815. return null;
  4816. }
  4817. }
  4818. /**
  4819. * Get the URL
  4820. *
  4821. * @return string|null
  4822. */
  4823. public function get_link()
  4824. {
  4825. if ($this->link !== null)
  4826. {
  4827. return urldecode($this->link);
  4828. }
  4829. else
  4830. {
  4831. return null;
  4832. }
  4833. }
  4834. /**
  4835. * Get the medium
  4836. *
  4837. * @link http://www.rssboard.org/media-rss#media-content
  4838. * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
  4839. */
  4840. public function get_medium()
  4841. {
  4842. if ($this->medium !== null)
  4843. {
  4844. return $this->medium;
  4845. }
  4846. else
  4847. {
  4848. return null;
  4849. }
  4850. }
  4851. /**
  4852. * Get the player URL
  4853. *
  4854. * Typically the same as {@see get_permalink()}
  4855. * @return string|null Player URL
  4856. */
  4857. public function get_player()
  4858. {
  4859. if ($this->player !== null)
  4860. {
  4861. return $this->player;
  4862. }
  4863. else
  4864. {
  4865. return null;
  4866. }
  4867. }
  4868. /**
  4869. * Get a single rating
  4870. *
  4871. * @param int $key
  4872. * @return SimplePie_Rating|null
  4873. */
  4874. public function get_rating($key = 0)
  4875. {
  4876. $ratings = $this->get_ratings();
  4877. if (isset($ratings[$key]))
  4878. {
  4879. return $ratings[$key];
  4880. }
  4881. else
  4882. {
  4883. return null;
  4884. }
  4885. }
  4886. /**
  4887. * Get all ratings
  4888. *
  4889. * @return array|null Array of {@see SimplePie_Rating} objects
  4890. */
  4891. public function get_ratings()
  4892. {
  4893. if ($this->ratings !== null)
  4894. {
  4895. return $this->ratings;
  4896. }
  4897. else
  4898. {
  4899. return null;
  4900. }
  4901. }
  4902. /**
  4903. * Get a single restriction
  4904. *
  4905. * @param int $key
  4906. * @return SimplePie_Restriction|null
  4907. */
  4908. public function get_restriction($key = 0)
  4909. {
  4910. $restrictions = $this->get_restrictions();
  4911. if (isset($restrictions[$key]))
  4912. {
  4913. return $restrictions[$key];
  4914. }
  4915. else
  4916. {
  4917. return null;
  4918. }
  4919. }
  4920. /**
  4921. * Get all restrictions
  4922. *
  4923. * @return array|null Array of {@see SimplePie_Restriction} objects
  4924. */
  4925. public function get_restrictions()
  4926. {
  4927. if ($this->restrictions !== null)
  4928. {
  4929. return $this->restrictions;
  4930. }
  4931. else
  4932. {
  4933. return null;
  4934. }
  4935. }
  4936. /**
  4937. * Get the sampling rate (in kHz)
  4938. *
  4939. * @return string|null
  4940. */
  4941. public function get_sampling_rate()
  4942. {
  4943. if ($this->samplingrate !== null)
  4944. {
  4945. return $this->samplingrate;
  4946. }
  4947. else
  4948. {
  4949. return null;
  4950. }
  4951. }
  4952. /**
  4953. * Get the file size (in MiB)
  4954. *
  4955. * @return float|null File size in mebibytes (1048 bytes)
  4956. */
  4957. public function get_size()
  4958. {
  4959. $length = $this->get_length();
  4960. if ($length !== null)
  4961. {
  4962. return round($length/1048576, 2);
  4963. }
  4964. else
  4965. {
  4966. return null;
  4967. }
  4968. }
  4969. /**
  4970. * Get a single thumbnail
  4971. *
  4972. * @param int $key
  4973. * @return string|null Thumbnail URL
  4974. */
  4975. public function get_thumbnail($key = 0)
  4976. {
  4977. $thumbnails = $this->get_thumbnails();
  4978. if (isset($thumbnails[$key]))
  4979. {
  4980. return $thumbnails[$key];
  4981. }
  4982. else
  4983. {
  4984. return null;
  4985. }
  4986. }
  4987. /**
  4988. * Get all thumbnails
  4989. *
  4990. * @return array|null Array of thumbnail URLs
  4991. */
  4992. public function get_thumbnails()
  4993. {
  4994. if ($this->thumbnails !== null)
  4995. {
  4996. return $this->thumbnails;
  4997. }
  4998. else
  4999. {
  5000. return null;
  5001. }
  5002. }
  5003. /**
  5004. * Get the title
  5005. *
  5006. * @return string|null
  5007. */
  5008. public function get_title()
  5009. {
  5010. if ($this->title !== null)
  5011. {
  5012. return $this->title;
  5013. }
  5014. else
  5015. {
  5016. return null;
  5017. }
  5018. }
  5019. /**
  5020. * Get mimetype of the enclosure
  5021. *
  5022. * @see get_real_type()
  5023. * @return string|null MIME type
  5024. */
  5025. public function get_type()
  5026. {
  5027. if ($this->type !== null)
  5028. {
  5029. return $this->type;
  5030. }
  5031. else
  5032. {
  5033. return null;
  5034. }
  5035. }
  5036. /**
  5037. * Get the width
  5038. *
  5039. * @return string|null
  5040. */
  5041. public function get_width()
  5042. {
  5043. if ($this->width !== null)
  5044. {
  5045. return $this->width;
  5046. }
  5047. else
  5048. {
  5049. return null;
  5050. }
  5051. }
  5052. /**
  5053. * Embed the enclosure using `<embed>`
  5054. *
  5055. * @deprecated Use the second parameter to {@see embed} instead
  5056. *
  5057. * @param array|string $options See first paramter to {@see embed}
  5058. * @return string HTML string to output
  5059. */
  5060. public function native_embed($options='')
  5061. {
  5062. return $this->embed($options, true);
  5063. }
  5064. /**
  5065. * Embed the enclosure using Javascript
  5066. *
  5067. * `$options` is an array or comma-separated key:value string, with the
  5068. * following properties:
  5069. *
  5070. * - `alt` (string): Alternate content for when an end-user does not have
  5071. * the appropriate handler installed or when a file type is
  5072. * unsupported. Can be any text or HTML. Defaults to blank.
  5073. * - `altclass` (string): If a file type is unsupported, the end-user will
  5074. * see the alt text (above) linked directly to the content. That link
  5075. * will have this value as its class name. Defaults to blank.
  5076. * - `audio` (string): This is an image that should be used as a
  5077. * placeholder for audio files before they're loaded (QuickTime-only).
  5078. * Can be any relative or absolute URL. Defaults to blank.
  5079. * - `bgcolor` (string): The background color for the media, if not
  5080. * already transparent. Defaults to `#ffffff`.
  5081. * - `height` (integer): The height of the embedded media. Accepts any
  5082. * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
  5083. * and it is recommended that you use this default.
  5084. * - `loop` (boolean): Do you want the media to loop when its done?
  5085. * Defaults to `false`.
  5086. * - `mediaplayer` (string): The location of the included
  5087. * `mediaplayer.swf` file. This allows for the playback of Flash Video
  5088. * (`.flv`) files, and is the default handler for non-Odeo MP3's.
  5089. * Defaults to blank.
  5090. * - `video` (string): This is an image that should be used as a
  5091. * placeholder for video files before they're loaded (QuickTime-only).
  5092. * Can be any relative or absolute URL. Defaults to blank.
  5093. * - `width` (integer): The width of the embedded media. Accepts any
  5094. * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
  5095. * and it is recommended that you use this default.
  5096. * - `widescreen` (boolean): Is the enclosure widescreen or standard?
  5097. * This applies only to video enclosures, and will automatically resize
  5098. * the content appropriately. Defaults to `false`, implying 4:3 mode.
  5099. *
  5100. * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
  5101. * will default to 480x360 video resolution. Widescreen (16:9) mode with
  5102. * `width` and `height` set to `auto` will default to 480x270 video resolution.
  5103. *
  5104. * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
  5105. * @param array|string $options Comma-separated key:value list, or array
  5106. * @param bool $native Use `<embed>`
  5107. * @return string HTML string to output
  5108. */
  5109. public function embed($options = '', $native = false)
  5110. {
  5111. // Set up defaults
  5112. $audio = '';
  5113. $video = '';
  5114. $alt = '';
  5115. $altclass = '';
  5116. $loop = 'false';
  5117. $width = 'auto';
  5118. $height = 'auto';
  5119. $bgcolor = '#ffffff';
  5120. $mediaplayer = '';
  5121. $widescreen = false;
  5122. $handler = $this->get_handler();
  5123. $type = $this->get_real_type();
  5124. // Process options and reassign values as necessary
  5125. if (is_array($options))
  5126. {
  5127. extract($options);
  5128. }
  5129. else
  5130. {
  5131. $options = explode(',', $options);
  5132. foreach($options as $option)
  5133. {
  5134. $opt = explode(':', $option, 2);
  5135. if (isset($opt[0], $opt[1]))
  5136. {
  5137. $opt[0] = trim($opt[0]);
  5138. $opt[1] = trim($opt[1]);
  5139. switch ($opt[0])
  5140. {
  5141. case 'audio':
  5142. $audio = $opt[1];
  5143. break;
  5144. case 'video':
  5145. $video = $opt[1];
  5146. break;
  5147. case 'alt':
  5148. $alt = $opt[1];
  5149. break;
  5150. case 'altclass':
  5151. $altclass = $opt[1];
  5152. break;
  5153. case 'loop':
  5154. $loop = $opt[1];
  5155. break;
  5156. case 'width':
  5157. $width = $opt[1];
  5158. break;
  5159. case 'height':
  5160. $height = $opt[1];
  5161. break;
  5162. case 'bgcolor':
  5163. $bgcolor = $opt[1];
  5164. break;
  5165. case 'mediaplayer':
  5166. $mediaplayer = $opt[1];
  5167. break;
  5168. case 'widescreen':
  5169. $widescreen = $opt[1];
  5170. break;
  5171. }
  5172. }
  5173. }
  5174. }
  5175. $mime = explode('/', $type, 2);
  5176. $mime = $mime[0];
  5177. // Process values for 'auto'
  5178. if ($width === 'auto')
  5179. {
  5180. if ($mime === 'video')
  5181. {
  5182. if ($height === 'auto')
  5183. {
  5184. $width = 480;
  5185. }
  5186. elseif ($widescreen)
  5187. {
  5188. $width = round((intval($height)/9)*16);
  5189. }
  5190. else
  5191. {
  5192. $width = round((intval($height)/3)*4);
  5193. }
  5194. }
  5195. else
  5196. {
  5197. $width = '100%';
  5198. }
  5199. }
  5200. if ($height === 'auto')
  5201. {
  5202. if ($mime === 'audio')
  5203. {
  5204. $height = 0;
  5205. }
  5206. elseif ($mime === 'video')
  5207. {
  5208. if ($width === 'auto')
  5209. {
  5210. if ($widescreen)
  5211. {
  5212. $height = 270;
  5213. }
  5214. else
  5215. {
  5216. $height = 360;
  5217. }
  5218. }
  5219. elseif ($widescreen)
  5220. {
  5221. $height = round((intval($width)/16)*9);
  5222. }
  5223. else
  5224. {
  5225. $height = round((intval($width)/4)*3);
  5226. }
  5227. }
  5228. else
  5229. {
  5230. $height = 376;
  5231. }
  5232. }
  5233. elseif ($mime === 'audio')
  5234. {
  5235. $height = 0;
  5236. }
  5237. // Set proper placeholder value
  5238. if ($mime === 'audio')
  5239. {
  5240. $placeholder = $audio;
  5241. }
  5242. elseif ($mime === 'video')
  5243. {
  5244. $placeholder = $video;
  5245. }
  5246. $embed = '';
  5247. // Flash
  5248. if ($handler === 'flash')
  5249. {
  5250. if ($native)
  5251. {
  5252. $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
  5253. }
  5254. else
  5255. {
  5256. $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
  5257. }
  5258. }
  5259. // Flash Media Player file types.
  5260. // Preferred handler for MP3 file types.
  5261. elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
  5262. {
  5263. $height += 20;
  5264. if ($native)
  5265. {
  5266. $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
  5267. }
  5268. else
  5269. {
  5270. $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
  5271. }
  5272. }
  5273. // QuickTime 7 file types. Need to test with QuickTime 6.
  5274. // Only handle MP3's if the Flash Media Player is not present.
  5275. elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
  5276. {
  5277. $height += 16;
  5278. if ($native)
  5279. {
  5280. if ($placeholder !== '')
  5281. {
  5282. $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
  5283. }
  5284. else
  5285. {
  5286. $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
  5287. }
  5288. }
  5289. else
  5290. {
  5291. $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
  5292. }
  5293. }
  5294. // Windows Media
  5295. elseif ($handler === 'wmedia')
  5296. {
  5297. $height += 45;
  5298. if ($native)
  5299. {
  5300. $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
  5301. }
  5302. else
  5303. {
  5304. $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
  5305. }
  5306. }
  5307. // Everything else
  5308. else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
  5309. return $embed;
  5310. }
  5311. /**
  5312. * Get the real media type
  5313. *
  5314. * Often, feeds lie to us, necessitating a bit of deeper inspection. This
  5315. * converts types to their canonical representations based on the file
  5316. * extension
  5317. *
  5318. * @see get_type()
  5319. * @param bool $find_handler Internal use only, use {@see get_handler()} instead
  5320. * @return string MIME type
  5321. */
  5322. public function get_real_type($find_handler = false)
  5323. {
  5324. // Mime-types by handler.
  5325. $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
  5326. $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
  5327. $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
  5328. $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
  5329. $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
  5330. if ($this->get_type() !== null)
  5331. {
  5332. $type = strtolower($this->type);
  5333. }
  5334. else
  5335. {
  5336. $type = null;
  5337. }
  5338. // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
  5339. if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
  5340. {
  5341. switch (strtolower($this->get_extension()))
  5342. {
  5343. // Audio mime-types
  5344. case 'aac':
  5345. case 'adts':
  5346. $type = 'audio/acc';
  5347. break;
  5348. case 'aif':
  5349. case 'aifc':
  5350. case 'aiff':
  5351. case 'cdda':
  5352. $type = 'audio/aiff';
  5353. break;
  5354. case 'bwf':
  5355. $type = 'audio/wav';
  5356. break;
  5357. case 'kar':
  5358. case 'mid':
  5359. case 'midi':
  5360. case 'smf':
  5361. $type = 'audio/midi';
  5362. break;
  5363. case 'm4a':
  5364. $type = 'audio/x-m4a';
  5365. break;
  5366. case 'mp3':
  5367. case 'swa':
  5368. $type = 'audio/mp3';
  5369. break;
  5370. case 'wav':
  5371. $type = 'audio/wav';
  5372. break;
  5373. case 'wax':
  5374. $type = 'audio/x-ms-wax';
  5375. break;
  5376. case 'wma':
  5377. $type = 'audio/x-ms-wma';
  5378. break;
  5379. // Video mime-types
  5380. case '3gp':
  5381. case '3gpp':
  5382. $type = 'video/3gpp';
  5383. break;
  5384. case '3g2':
  5385. case '3gp2':
  5386. $type = 'video/3gpp2';
  5387. break;
  5388. case 'asf':
  5389. $type = 'video/x-ms-asf';
  5390. break;
  5391. case 'flv':
  5392. $type = 'video/x-flv';
  5393. break;
  5394. case 'm1a':
  5395. case 'm1s':
  5396. case 'm1v':
  5397. case 'm15':
  5398. case 'm75':
  5399. case 'mp2':
  5400. case 'mpa':
  5401. case 'mpeg':
  5402. case 'mpg':
  5403. case 'mpm':
  5404. case 'mpv':
  5405. $type = 'video/mpeg';
  5406. break;
  5407. case 'm4v':
  5408. $type = 'video/x-m4v';
  5409. break;
  5410. case 'mov':
  5411. case 'qt':
  5412. $type = 'video/quicktime';
  5413. break;
  5414. case 'mp4':
  5415. case 'mpg4':
  5416. $type = 'video/mp4';
  5417. break;
  5418. case 'sdv':
  5419. $type = 'video/sd-video';
  5420. break;
  5421. case 'wm':
  5422. $type = 'video/x-ms-wm';
  5423. break;
  5424. case 'wmv':
  5425. $type = 'video/x-ms-wmv';
  5426. break;
  5427. case 'wvx':
  5428. $type = 'video/x-ms-wvx';
  5429. break;
  5430. // Flash mime-types
  5431. case 'spl':
  5432. $type = 'application/futuresplash';
  5433. break;
  5434. case 'swf':
  5435. $type = 'application/x-shockwave-flash';
  5436. break;
  5437. }
  5438. }
  5439. if ($find_handler)
  5440. {
  5441. if (in_array($type, $types_flash))
  5442. {
  5443. return 'flash';
  5444. }
  5445. elseif (in_array($type, $types_fmedia))
  5446. {
  5447. return 'fmedia';
  5448. }
  5449. elseif (in_array($type, $types_quicktime))
  5450. {
  5451. return 'quicktime';
  5452. }
  5453. elseif (in_array($type, $types_wmedia))
  5454. {
  5455. return 'wmedia';
  5456. }
  5457. elseif (in_array($type, $types_mp3))
  5458. {
  5459. return 'mp3';
  5460. }
  5461. else
  5462. {
  5463. return null;
  5464. }
  5465. }
  5466. else
  5467. {
  5468. return $type;
  5469. }
  5470. }
  5471. }
  5472. /**
  5473. * Parses the XML Declaration
  5474. *
  5475. * @package SimplePie
  5476. * @subpackage Parsing
  5477. */
  5478. class SimplePie_XML_Declaration_Parser
  5479. {
  5480. /**
  5481. * XML Version
  5482. *
  5483. * @access public
  5484. * @var string
  5485. */
  5486. var $version = '1.0';
  5487. /**
  5488. * Encoding
  5489. *
  5490. * @access public
  5491. * @var string
  5492. */
  5493. var $encoding = 'UTF-8';
  5494. /**
  5495. * Standalone
  5496. *
  5497. * @access public
  5498. * @var bool
  5499. */
  5500. var $standalone = false;
  5501. /**
  5502. * Current state of the state machine
  5503. *
  5504. * @access private
  5505. * @var string
  5506. */
  5507. var $state = 'before_version_name';
  5508. /**
  5509. * Input data
  5510. *
  5511. * @access private
  5512. * @var string
  5513. */
  5514. var $data = '';
  5515. /**
  5516. * Input data length (to avoid calling strlen() everytime this is needed)
  5517. *
  5518. * @access private
  5519. * @var int
  5520. */
  5521. var $data_length = 0;
  5522. /**
  5523. * Current position of the pointer
  5524. *
  5525. * @var int
  5526. * @access private
  5527. */
  5528. var $position = 0;
  5529. /**
  5530. * Create an instance of the class with the input data
  5531. *
  5532. * @access public
  5533. * @param string $data Input data
  5534. */
  5535. public function __construct($data)
  5536. {
  5537. $this->data = $data;
  5538. $this->data_length = strlen($this->data);
  5539. }
  5540. /**
  5541. * Parse the input data
  5542. *
  5543. * @access public
  5544. * @return bool true on success, false on failure
  5545. */
  5546. public function parse()
  5547. {
  5548. while ($this->state && $this->state !== 'emit' && $this->has_data())
  5549. {
  5550. $state = $this->state;
  5551. $this->$state();
  5552. }
  5553. $this->data = '';
  5554. if ($this->state === 'emit')
  5555. {
  5556. return true;
  5557. }
  5558. else
  5559. {
  5560. $this->version = '';
  5561. $this->encoding = '';
  5562. $this->standalone = '';
  5563. return false;
  5564. }
  5565. }
  5566. /**
  5567. * Check whether there is data beyond the pointer
  5568. *
  5569. * @access private
  5570. * @return bool true if there is further data, false if not
  5571. */
  5572. public function has_data()
  5573. {
  5574. return (bool) ($this->position < $this->data_length);
  5575. }
  5576. /**
  5577. * Advance past any whitespace
  5578. *
  5579. * @return int Number of whitespace characters passed
  5580. */
  5581. public function skip_whitespace()
  5582. {
  5583. $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
  5584. $this->position += $whitespace;
  5585. return $whitespace;
  5586. }
  5587. /**
  5588. * Read value
  5589. */
  5590. public function get_value()
  5591. {
  5592. $quote = substr($this->data, $this->position, 1);
  5593. if ($quote === '"' || $quote === "'")
  5594. {
  5595. $this->position++;
  5596. $len = strcspn($this->data, $quote, $this->position);
  5597. if ($this->has_data())
  5598. {
  5599. $value = substr($this->data, $this->position, $len);
  5600. $this->position += $len + 1;
  5601. return $value;
  5602. }
  5603. }
  5604. return false;
  5605. }
  5606. public function before_version_name()
  5607. {
  5608. if ($this->skip_whitespace())
  5609. {
  5610. $this->state = 'version_name';
  5611. }
  5612. else
  5613. {
  5614. $this->state = false;
  5615. }
  5616. }
  5617. public function version_name()
  5618. {
  5619. if (substr($this->data, $this->position, 7) === 'version')
  5620. {
  5621. $this->position += 7;
  5622. $this->skip_whitespace();
  5623. $this->state = 'version_equals';
  5624. }
  5625. else
  5626. {
  5627. $this->state = false;
  5628. }
  5629. }
  5630. public function version_equals()
  5631. {
  5632. if (substr($this->data, $this->position, 1) === '=')
  5633. {
  5634. $this->position++;
  5635. $this->skip_whitespace();
  5636. $this->state = 'version_value';
  5637. }
  5638. else
  5639. {
  5640. $this->state = false;
  5641. }
  5642. }
  5643. public function version_value()
  5644. {
  5645. if ($this->version = $this->get_value())
  5646. {
  5647. $this->skip_whitespace();
  5648. if ($this->has_data())
  5649. {
  5650. $this->state = 'encoding_name';
  5651. }
  5652. else
  5653. {
  5654. $this->state = 'emit';
  5655. }
  5656. }
  5657. else
  5658. {
  5659. $this->state = false;
  5660. }
  5661. }
  5662. public function encoding_name()
  5663. {
  5664. if (substr($this->data, $this->position, 8) === 'encoding')
  5665. {
  5666. $this->position += 8;
  5667. $this->skip_whitespace();
  5668. $this->state = 'encoding_equals';
  5669. }
  5670. else
  5671. {
  5672. $this->state = 'standalone_name';
  5673. }
  5674. }
  5675. public function encoding_equals()
  5676. {
  5677. if (substr($this->data, $this->position, 1) === '=')
  5678. {
  5679. $this->position++;
  5680. $this->skip_whitespace();
  5681. $this->state = 'encoding_value';
  5682. }
  5683. else
  5684. {
  5685. $this->state = false;
  5686. }
  5687. }
  5688. public function encoding_value()
  5689. {
  5690. if ($this->encoding = $this->get_value())
  5691. {
  5692. $this->skip_whitespace();
  5693. if ($this->has_data())
  5694. {
  5695. $this->state = 'standalone_name';
  5696. }
  5697. else
  5698. {
  5699. $this->state = 'emit';
  5700. }
  5701. }
  5702. else
  5703. {
  5704. $this->state = false;
  5705. }
  5706. }
  5707. public function standalone_name()
  5708. {
  5709. if (substr($this->data, $this->position, 10) === 'standalone')
  5710. {
  5711. $this->position += 10;
  5712. $this->skip_whitespace();
  5713. $this->state = 'standalone_equals';
  5714. }
  5715. else
  5716. {
  5717. $this->state = false;
  5718. }
  5719. }
  5720. public function standalone_equals()
  5721. {
  5722. if (substr($this->data, $this->position, 1) === '=')
  5723. {
  5724. $this->position++;
  5725. $this->skip_whitespace();
  5726. $this->state = 'standalone_value';
  5727. }
  5728. else
  5729. {
  5730. $this->state = false;
  5731. }
  5732. }
  5733. public function standalone_value()
  5734. {
  5735. if ($standalone = $this->get_value())
  5736. {
  5737. switch ($standalone)
  5738. {
  5739. case 'yes':
  5740. $this->standalone = true;
  5741. break;
  5742. case 'no':
  5743. $this->standalone = false;
  5744. break;
  5745. default:
  5746. $this->state = false;
  5747. return;
  5748. }
  5749. $this->skip_whitespace();
  5750. if ($this->has_data())
  5751. {
  5752. $this->state = false;
  5753. }
  5754. else
  5755. {
  5756. $this->state = 'emit';
  5757. }
  5758. }
  5759. else
  5760. {
  5761. $this->state = false;
  5762. }
  5763. }
  5764. }
  5765. /**
  5766. * Used for fetching remote files and reading local files
  5767. *
  5768. * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
  5769. *
  5770. * This class can be overloaded with {@see SimplePie::set_file_class()}
  5771. *
  5772. * @package SimplePie
  5773. * @subpackage HTTP
  5774. * @todo Move to properly supporting RFC2616 (HTTP/1.1)
  5775. */
  5776. class SimplePie_File
  5777. {
  5778. var $url;
  5779. var $useragent;
  5780. var $success = true;
  5781. var $headers = array();
  5782. var $body;
  5783. var $status_code;
  5784. var $redirects = 0;
  5785. var $error;
  5786. var $method = SIMPLEPIE_FILE_SOURCE_NONE;
  5787. public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
  5788. {
  5789. if (class_exists('idna_convert'))
  5790. {
  5791. $idn = new idna_convert();
  5792. $parsed = SimplePie_Misc::parse_url($url);
  5793. $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
  5794. }
  5795. $this->url = $url;
  5796. $this->useragent = $useragent;
  5797. if (preg_match('/^http(s)?:\/\//i', $url))
  5798. {
  5799. if ($useragent === null)
  5800. {
  5801. $useragent = ini_get('user_agent');
  5802. $this->useragent = $useragent;
  5803. }
  5804. if (!is_array($headers))
  5805. {
  5806. $headers = array();
  5807. }
  5808. if (!$force_fsockopen && function_exists('curl_exec'))
  5809. {
  5810. $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
  5811. $fp = curl_init();
  5812. $headers2 = array();
  5813. foreach ($headers as $key => $value)
  5814. {
  5815. $headers2[] = "$key: $value";
  5816. }
  5817. if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
  5818. {
  5819. curl_setopt($fp, CURLOPT_ENCODING, '');
  5820. }
  5821. curl_setopt($fp, CURLOPT_URL, $url);
  5822. curl_setopt($fp, CURLOPT_HEADER, 1);
  5823. curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
  5824. curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
  5825. curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
  5826. curl_setopt($fp, CURLOPT_REFERER, $url);
  5827. curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
  5828. curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
  5829. if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
  5830. {
  5831. curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
  5832. curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
  5833. }
  5834. $this->headers = curl_exec($fp);
  5835. if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
  5836. {
  5837. curl_setopt($fp, CURLOPT_ENCODING, 'none');
  5838. $this->headers = curl_exec($fp);
  5839. }
  5840. if (curl_errno($fp))
  5841. {
  5842. $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
  5843. $this->success = false;
  5844. }
  5845. else
  5846. {
  5847. $info = curl_getinfo($fp);
  5848. curl_close($fp);
  5849. $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
  5850. $this->headers = array_pop($this->headers);
  5851. $parser = new SimplePie_HTTP_Parser($this->headers);
  5852. if ($parser->parse())
  5853. {
  5854. $this->headers = $parser->headers;
  5855. $this->body = $parser->body;
  5856. $this->status_code = $parser->status_code;
  5857. if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
  5858. {
  5859. $this->redirects++;
  5860. $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
  5861. return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
  5862. }
  5863. }
  5864. }
  5865. }
  5866. else
  5867. {
  5868. $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
  5869. $url_parts = parse_url($url);
  5870. $socket_host = $url_parts['host'];
  5871. if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
  5872. {
  5873. $socket_host = "ssl://$url_parts[host]";
  5874. $url_parts['port'] = 443;
  5875. }
  5876. if (!isset($url_parts['port']))
  5877. {
  5878. $url_parts['port'] = 80;
  5879. }
  5880. $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
  5881. if (!$fp)
  5882. {
  5883. $this->error = 'fsockopen error: ' . $errstr;
  5884. $this->success = false;
  5885. }
  5886. else
  5887. {
  5888. stream_set_timeout($fp, $timeout);
  5889. if (isset($url_parts['path']))
  5890. {
  5891. if (isset($url_parts['query']))
  5892. {
  5893. $get = "$url_parts[path]?$url_parts[query]";
  5894. }
  5895. else
  5896. {
  5897. $get = $url_parts['path'];
  5898. }
  5899. }
  5900. else
  5901. {
  5902. $get = '/';
  5903. }
  5904. $out = "GET $get HTTP/1.1\r\n";
  5905. $out .= "Host: $url_parts[host]\r\n";
  5906. $out .= "User-Agent: $useragent\r\n";
  5907. if (extension_loaded('zlib'))
  5908. {
  5909. $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
  5910. }
  5911. if (isset($url_parts['user']) && isset($url_parts['pass']))
  5912. {
  5913. $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
  5914. }
  5915. foreach ($headers as $key => $value)
  5916. {
  5917. $out .= "$key: $value\r\n";
  5918. }
  5919. $out .= "Connection: Close\r\n\r\n";
  5920. fwrite($fp, $out);
  5921. $info = stream_get_meta_data($fp);
  5922. $this->headers = '';
  5923. while (!$info['eof'] && !$info['timed_out'])
  5924. {
  5925. $this->headers .= fread($fp, 1160);
  5926. $info = stream_get_meta_data($fp);
  5927. }
  5928. if (!$info['timed_out'])
  5929. {
  5930. $parser = new SimplePie_HTTP_Parser($this->headers);
  5931. if ($parser->parse())
  5932. {
  5933. $this->headers = $parser->headers;
  5934. $this->body = $parser->body;
  5935. $this->status_code = $parser->status_code;
  5936. if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
  5937. {
  5938. $this->redirects++;
  5939. $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
  5940. return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
  5941. }
  5942. if (isset($this->headers['content-encoding']))
  5943. {
  5944. // Hey, we act dumb elsewhere, so let's do that here too
  5945. switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
  5946. {
  5947. case 'gzip':
  5948. case 'x-gzip':
  5949. $decoder = new SimplePie_gzdecode($this->body);
  5950. if (!$decoder->parse())
  5951. {
  5952. $this->error = 'Unable to decode HTTP "gzip" stream';
  5953. $this->success = false;
  5954. }
  5955. else
  5956. {
  5957. $this->body = $decoder->data;
  5958. }
  5959. break;
  5960. case 'deflate':
  5961. if (($decompressed = gzinflate($this->body)) !== false)
  5962. {
  5963. $this->body = $decompressed;
  5964. }
  5965. else if (($decompressed = gzuncompress($this->body)) !== false)
  5966. {
  5967. $this->body = $decompressed;
  5968. }
  5969. else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
  5970. {
  5971. $this->body = $decompressed;
  5972. }
  5973. else
  5974. {
  5975. $this->error = 'Unable to decode HTTP "deflate" stream';
  5976. $this->success = false;
  5977. }
  5978. break;
  5979. default:
  5980. $this->error = 'Unknown content coding';
  5981. $this->success = false;
  5982. }
  5983. }
  5984. }
  5985. }
  5986. else
  5987. {
  5988. $this->error = 'fsocket timed out';
  5989. $this->success = false;
  5990. }
  5991. fclose($fp);
  5992. }
  5993. }
  5994. }
  5995. else
  5996. {
  5997. $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
  5998. if (!$this->body = file_get_contents($url))
  5999. {
  6000. $this->error = 'file_get_contents could not read the file';
  6001. $this->success = false;
  6002. }
  6003. }
  6004. }
  6005. }
  6006. /**
  6007. * IRI parser/serialiser/normaliser
  6008. *
  6009. * @package SimplePie
  6010. * @subpackage HTTP
  6011. * @author Geoffrey Sneddon
  6012. * @author Steve Minutillo
  6013. * @author Ryan McCue
  6014. * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
  6015. * @license http://www.opensource.org/licenses/bsd-license.php
  6016. */
  6017. class SimplePie_IRI
  6018. {
  6019. /**
  6020. * Scheme
  6021. *
  6022. * @var string
  6023. */
  6024. protected $scheme = null;
  6025. /**
  6026. * User Information
  6027. *
  6028. * @var string
  6029. */
  6030. protected $iuserinfo = null;
  6031. /**
  6032. * ihost
  6033. *
  6034. * @var string
  6035. */
  6036. protected $ihost = null;
  6037. /**
  6038. * Port
  6039. *
  6040. * @var string
  6041. */
  6042. protected $port = null;
  6043. /**
  6044. * ipath
  6045. *
  6046. * @var string
  6047. */
  6048. protected $ipath = '';
  6049. /**
  6050. * iquery
  6051. *
  6052. * @var string
  6053. */
  6054. protected $iquery = null;
  6055. /**
  6056. * ifragment
  6057. *
  6058. * @var string
  6059. */
  6060. protected $ifragment = null;
  6061. /**
  6062. * Normalization database
  6063. *
  6064. * Each key is the scheme, each value is an array with each key as the IRI
  6065. * part and value as the default value for that part.
  6066. */
  6067. protected $normalization = array(
  6068. 'acap' => array(
  6069. 'port' => 674
  6070. ),
  6071. 'dict' => array(
  6072. 'port' => 2628
  6073. ),
  6074. 'file' => array(
  6075. 'ihost' => 'localhost'
  6076. ),
  6077. 'http' => array(
  6078. 'port' => 80,
  6079. 'ipath' => '/'
  6080. ),
  6081. 'https' => array(
  6082. 'port' => 443,
  6083. 'ipath' => '/'
  6084. ),
  6085. );
  6086. /**
  6087. * Return the entire IRI when you try and read the object as a string
  6088. *
  6089. * @return string
  6090. */
  6091. public function __toString()
  6092. {
  6093. return $this->get_iri();
  6094. }
  6095. /**
  6096. * Overload __set() to provide access via properties
  6097. *
  6098. * @param string $name Property name
  6099. * @param mixed $value Property value
  6100. */
  6101. public function __set($name, $value)
  6102. {
  6103. if (method_exists($this, 'set_' . $name))
  6104. {
  6105. call_user_func(array($this, 'set_' . $name), $value);
  6106. }
  6107. elseif (
  6108. $name === 'iauthority'
  6109. || $name === 'iuserinfo'
  6110. || $name === 'ihost'
  6111. || $name === 'ipath'
  6112. || $name === 'iquery'
  6113. || $name === 'ifragment'
  6114. )
  6115. {
  6116. call_user_func(array($this, 'set_' . substr($name, 1)), $value);
  6117. }
  6118. }
  6119. /**
  6120. * Overload __get() to provide access via properties
  6121. *
  6122. * @param string $name Property name
  6123. * @return mixed
  6124. */
  6125. public function __get($name)
  6126. {
  6127. // isset() returns false for null, we don't want to do that
  6128. // Also why we use array_key_exists below instead of isset()
  6129. $props = get_object_vars($this);
  6130. if (
  6131. $name === 'iri' ||
  6132. $name === 'uri' ||
  6133. $name === 'iauthority' ||
  6134. $name === 'authority'
  6135. )
  6136. {
  6137. $return = $this->{"get_$name"}();
  6138. }
  6139. elseif (array_key_exists($name, $props))
  6140. {
  6141. $return = $this->$name;
  6142. }
  6143. // host -> ihost
  6144. elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
  6145. {
  6146. $name = $prop;
  6147. $return = $this->$prop;
  6148. }
  6149. // ischeme -> scheme
  6150. elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
  6151. {
  6152. $name = $prop;
  6153. $return = $this->$prop;
  6154. }
  6155. else
  6156. {
  6157. trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
  6158. $return = null;
  6159. }
  6160. if ($return === null && isset($this->normalization[$this->scheme][$name]))
  6161. {
  6162. return $this->normalization[$this->scheme][$name];
  6163. }
  6164. else
  6165. {
  6166. return $return;
  6167. }
  6168. }
  6169. /**
  6170. * Overload __isset() to provide access via properties
  6171. *
  6172. * @param string $name Property name
  6173. * @return bool
  6174. */
  6175. public function __isset($name)
  6176. {
  6177. if (method_exists($this, 'get_' . $name) || isset($this->$name))
  6178. {
  6179. return true;
  6180. }
  6181. else
  6182. {
  6183. return false;
  6184. }
  6185. }
  6186. /**
  6187. * Overload __unset() to provide access via properties
  6188. *
  6189. * @param string $name Property name
  6190. */
  6191. public function __unset($name)
  6192. {
  6193. if (method_exists($this, 'set_' . $name))
  6194. {
  6195. call_user_func(array($this, 'set_' . $name), '');
  6196. }
  6197. }
  6198. /**
  6199. * Create a new IRI object, from a specified string
  6200. *
  6201. * @param string $iri
  6202. */
  6203. public function __construct($iri = null)
  6204. {
  6205. $this->set_iri($iri);
  6206. }
  6207. /**
  6208. * Create a new IRI object by resolving a relative IRI
  6209. *
  6210. * Returns false if $base is not absolute, otherwise an IRI.
  6211. *
  6212. * @param IRI|string $base (Absolute) Base IRI
  6213. * @param IRI|string $relative Relative IRI
  6214. * @return IRI|false
  6215. */
  6216. public static function absolutize($base, $relative)
  6217. {
  6218. if (!($relative instanceof SimplePie_IRI))
  6219. {
  6220. $relative = new SimplePie_IRI($relative);
  6221. }
  6222. if (!$relative->is_valid())
  6223. {
  6224. return false;
  6225. }
  6226. elseif ($relative->scheme !== null)
  6227. {
  6228. return clone $relative;
  6229. }
  6230. else
  6231. {
  6232. if (!($base instanceof SimplePie_IRI))
  6233. {
  6234. $base = new SimplePie_IRI($base);
  6235. }
  6236. if ($base->scheme !== null && $base->is_valid())
  6237. {
  6238. if ($relative->get_iri() !== '')
  6239. {
  6240. if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
  6241. {
  6242. $target = clone $relative;
  6243. $target->scheme = $base->scheme;
  6244. }
  6245. else
  6246. {
  6247. $target = new SimplePie_IRI;
  6248. $target->scheme = $base->scheme;
  6249. $target->iuserinfo = $base->iuserinfo;
  6250. $target->ihost = $base->ihost;
  6251. $target->port = $base->port;
  6252. if ($relative->ipath !== '')
  6253. {
  6254. if ($relative->ipath[0] === '/')
  6255. {
  6256. $target->ipath = $relative->ipath;
  6257. }
  6258. elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
  6259. {
  6260. $target->ipath = '/' . $relative->ipath;
  6261. }
  6262. elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
  6263. {
  6264. $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
  6265. }
  6266. else
  6267. {
  6268. $target->ipath = $relative->ipath;
  6269. }
  6270. $target->ipath = $target->remove_dot_segments($target->ipath);
  6271. $target->iquery = $relative->iquery;
  6272. }
  6273. else
  6274. {
  6275. $target->ipath = $base->ipath;
  6276. if ($relative->iquery !== null)
  6277. {
  6278. $target->iquery = $relative->iquery;
  6279. }
  6280. elseif ($base->iquery !== null)
  6281. {
  6282. $target->iquery = $base->iquery;
  6283. }
  6284. }
  6285. $target->ifragment = $relative->ifragment;
  6286. }
  6287. }
  6288. else
  6289. {
  6290. $target = clone $base;
  6291. $target->ifragment = null;
  6292. }
  6293. $target->scheme_normalization();
  6294. return $target;
  6295. }
  6296. else
  6297. {
  6298. return false;
  6299. }
  6300. }
  6301. }
  6302. /**
  6303. * Parse an IRI into scheme/authority/path/query/fragment segments
  6304. *
  6305. * @param string $iri
  6306. * @return array
  6307. */
  6308. protected function parse_iri($iri)
  6309. {
  6310. $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
  6311. if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
  6312. {
  6313. if ($match[1] === '')
  6314. {
  6315. $match['scheme'] = null;
  6316. }
  6317. if (!isset($match[3]) || $match[3] === '')
  6318. {
  6319. $match['authority'] = null;
  6320. }
  6321. if (!isset($match[5]))
  6322. {
  6323. $match['path'] = '';
  6324. }
  6325. if (!isset($match[6]) || $match[6] === '')
  6326. {
  6327. $match['query'] = null;
  6328. }
  6329. if (!isset($match[8]) || $match[8] === '')
  6330. {
  6331. $match['fragment'] = null;
  6332. }
  6333. return $match;
  6334. }
  6335. else
  6336. {
  6337. trigger_error('This should never happen', E_USER_ERROR);
  6338. die;
  6339. }
  6340. }
  6341. /**
  6342. * Remove dot segments from a path
  6343. *
  6344. * @param string $input
  6345. * @return string
  6346. */
  6347. protected function remove_dot_segments($input)
  6348. {
  6349. $output = '';
  6350. while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
  6351. {
  6352. // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
  6353. if (strpos($input, '../') === 0)
  6354. {
  6355. $input = substr($input, 3);
  6356. }
  6357. elseif (strpos($input, './') === 0)
  6358. {
  6359. $input = substr($input, 2);
  6360. }
  6361. // 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,
  6362. elseif (strpos($input, '/./') === 0)
  6363. {
  6364. $input = substr($input, 2);
  6365. }
  6366. elseif ($input === '/.')
  6367. {
  6368. $input = '/';
  6369. }
  6370. // 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,
  6371. elseif (strpos($input, '/../') === 0)
  6372. {
  6373. $input = substr($input, 3);
  6374. $output = substr_replace($output, '', strrpos($output, '/'));
  6375. }
  6376. elseif ($input === '/..')
  6377. {
  6378. $input = '/';
  6379. $output = substr_replace($output, '', strrpos($output, '/'));
  6380. }
  6381. // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
  6382. elseif ($input === '.' || $input === '..')
  6383. {
  6384. $input = '';
  6385. }
  6386. // 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
  6387. elseif (($pos = strpos($input, '/', 1)) !== false)
  6388. {
  6389. $output .= substr($input, 0, $pos);
  6390. $input = substr_replace($input, '', 0, $pos);
  6391. }
  6392. else
  6393. {
  6394. $output .= $input;
  6395. $input = '';
  6396. }
  6397. }
  6398. return $output . $input;
  6399. }
  6400. /**
  6401. * Replace invalid character with percent encoding
  6402. *
  6403. * @param string $string Input string
  6404. * @param string $extra_chars Valid characters not in iunreserved or
  6405. * iprivate (this is ASCII-only)
  6406. * @param bool $iprivate Allow iprivate
  6407. * @return string
  6408. */
  6409. protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
  6410. {
  6411. // Normalize as many pct-encoded sections as possible
  6412. $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
  6413. // Replace invalid percent characters
  6414. $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
  6415. // Add unreserved and % to $extra_chars (the latter is safe because all
  6416. // pct-encoded sections are now valid).
  6417. $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
  6418. // Now replace any bytes that aren't allowed with their pct-encoded versions
  6419. $position = 0;
  6420. $strlen = strlen($string);
  6421. while (($position += strspn($string, $extra_chars, $position)) < $strlen)
  6422. {
  6423. $value = ord($string[$position]);
  6424. // Start position
  6425. $start = $position;
  6426. // By default we are valid
  6427. $valid = true;
  6428. // No one byte sequences are valid due to the while.
  6429. // Two byte sequence:
  6430. if (($value & 0xE0) === 0xC0)
  6431. {
  6432. $character = ($value & 0x1F) << 6;
  6433. $length = 2;
  6434. $remaining = 1;
  6435. }
  6436. // Three byte sequence:
  6437. elseif (($value & 0xF0) === 0xE0)
  6438. {
  6439. $character = ($value & 0x0F) << 12;
  6440. $length = 3;
  6441. $remaining = 2;
  6442. }
  6443. // Four byte sequence:
  6444. elseif (($value & 0xF8) === 0xF0)
  6445. {
  6446. $character = ($value & 0x07) << 18;
  6447. $length = 4;
  6448. $remaining = 3;
  6449. }
  6450. // Invalid byte:
  6451. else
  6452. {
  6453. $valid = false;
  6454. $length = 1;
  6455. $remaining = 0;
  6456. }
  6457. if ($remaining)
  6458. {
  6459. if ($position + $length <= $strlen)
  6460. {
  6461. for ($position++; $remaining; $position++)
  6462. {
  6463. $value = ord($string[$position]);
  6464. // Check that the byte is valid, then add it to the character:
  6465. if (($value & 0xC0) === 0x80)
  6466. {
  6467. $character |= ($value & 0x3F) << (--$remaining * 6);
  6468. }
  6469. // If it is invalid, count the sequence as invalid and reprocess the current byte:
  6470. else
  6471. {
  6472. $valid = false;
  6473. $position--;
  6474. break;
  6475. }
  6476. }
  6477. }
  6478. else
  6479. {
  6480. $position = $strlen - 1;
  6481. $valid = false;
  6482. }
  6483. }
  6484. // Percent encode anything invalid or not in ucschar
  6485. if (
  6486. // Invalid sequences
  6487. !$valid
  6488. // Non-shortest form sequences are invalid
  6489. || $length > 1 && $character <= 0x7F
  6490. || $length > 2 && $character <= 0x7FF
  6491. || $length > 3 && $character <= 0xFFFF
  6492. // Outside of range of ucschar codepoints
  6493. // Noncharacters
  6494. || ($character & 0xFFFE) === 0xFFFE
  6495. || $character >= 0xFDD0 && $character <= 0xFDEF
  6496. || (
  6497. // Everything else not in ucschar
  6498. $character > 0xD7FF && $character < 0xF900
  6499. || $character < 0xA0
  6500. || $character > 0xEFFFD
  6501. )
  6502. && (
  6503. // Everything not in iprivate, if it applies
  6504. !$iprivate
  6505. || $character < 0xE000
  6506. || $character > 0x10FFFD
  6507. )
  6508. )
  6509. {
  6510. // If we were a character, pretend we weren't, but rather an error.
  6511. if ($valid)
  6512. $position--;
  6513. for ($j = $start; $j <= $position; $j++)
  6514. {
  6515. $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
  6516. $j += 2;
  6517. $position += 2;
  6518. $strlen += 2;
  6519. }
  6520. }
  6521. }
  6522. return $string;
  6523. }
  6524. /**
  6525. * Callback function for preg_replace_callback.
  6526. *
  6527. * Removes sequences of percent encoded bytes that represent UTF-8
  6528. * encoded characters in iunreserved
  6529. *
  6530. * @param array $match PCRE match
  6531. * @return string Replacement
  6532. */
  6533. protected function remove_iunreserved_percent_encoded($match)
  6534. {
  6535. // As we just have valid percent encoded sequences we can just explode
  6536. // and ignore the first member of the returned array (an empty string).
  6537. $bytes = explode('%', $match[0]);
  6538. // Initialize the new string (this is what will be returned) and that
  6539. // there are no bytes remaining in the current sequence (unsurprising
  6540. // at the first byte!).
  6541. $string = '';
  6542. $remaining = 0;
  6543. // Loop over each and every byte, and set $value to its value
  6544. for ($i = 1, $len = count($bytes); $i < $len; $i++)
  6545. {
  6546. $value = hexdec($bytes[$i]);
  6547. // If we're the first byte of sequence:
  6548. if (!$remaining)
  6549. {
  6550. // Start position
  6551. $start = $i;
  6552. // By default we are valid
  6553. $valid = true;
  6554. // One byte sequence:
  6555. if ($value <= 0x7F)
  6556. {
  6557. $character = $value;
  6558. $length = 1;
  6559. }
  6560. // Two byte sequence:
  6561. elseif (($value & 0xE0) === 0xC0)
  6562. {
  6563. $character = ($value & 0x1F) << 6;
  6564. $length = 2;
  6565. $remaining = 1;
  6566. }
  6567. // Three byte sequence:
  6568. elseif (($value & 0xF0) === 0xE0)
  6569. {
  6570. $character = ($value & 0x0F) << 12;
  6571. $length = 3;
  6572. $remaining = 2;
  6573. }
  6574. // Four byte sequence:
  6575. elseif (($value & 0xF8) === 0xF0)
  6576. {
  6577. $character = ($value & 0x07) << 18;
  6578. $length = 4;
  6579. $remaining = 3;
  6580. }
  6581. // Invalid byte:
  6582. else
  6583. {
  6584. $valid = false;
  6585. $remaining = 0;
  6586. }
  6587. }
  6588. // Continuation byte:
  6589. else
  6590. {
  6591. // Check that the byte is valid, then add it to the character:
  6592. if (($value & 0xC0) === 0x80)
  6593. {
  6594. $remaining--;
  6595. $character |= ($value & 0x3F) << ($remaining * 6);
  6596. }
  6597. // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
  6598. else
  6599. {
  6600. $valid = false;
  6601. $remaining = 0;
  6602. $i--;
  6603. }
  6604. }
  6605. // If we've reached the end of the current byte sequence, append it to Unicode::$data
  6606. if (!$remaining)
  6607. {
  6608. // Percent encode anything invalid or not in iunreserved
  6609. if (
  6610. // Invalid sequences
  6611. !$valid
  6612. // Non-shortest form sequences are invalid
  6613. || $length > 1 && $character <= 0x7F
  6614. || $length > 2 && $character <= 0x7FF
  6615. || $length > 3 && $character <= 0xFFFF
  6616. // Outside of range of iunreserved codepoints
  6617. || $character < 0x2D
  6618. || $character > 0xEFFFD
  6619. // Noncharacters
  6620. || ($character & 0xFFFE) === 0xFFFE
  6621. || $character >= 0xFDD0 && $character <= 0xFDEF
  6622. // Everything else not in iunreserved (this is all BMP)
  6623. || $character === 0x2F
  6624. || $character > 0x39 && $character < 0x41
  6625. || $character > 0x5A && $character < 0x61
  6626. || $character > 0x7A && $character < 0x7E
  6627. || $character > 0x7E && $character < 0xA0
  6628. || $character > 0xD7FF && $character < 0xF900
  6629. )
  6630. {
  6631. for ($j = $start; $j <= $i; $j++)
  6632. {
  6633. $string .= '%' . strtoupper($bytes[$j]);
  6634. }
  6635. }
  6636. else
  6637. {
  6638. for ($j = $start; $j <= $i; $j++)
  6639. {
  6640. $string .= chr(hexdec($bytes[$j]));
  6641. }
  6642. }
  6643. }
  6644. }
  6645. // If we have any bytes left over they are invalid (i.e., we are
  6646. // mid-way through a multi-byte sequence)
  6647. if ($remaining)
  6648. {
  6649. for ($j = $start; $j < $len; $j++)
  6650. {
  6651. $string .= '%' . strtoupper($bytes[$j]);
  6652. }
  6653. }
  6654. return $string;
  6655. }
  6656. protected function scheme_normalization()
  6657. {
  6658. if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
  6659. {
  6660. $this->iuserinfo = null;
  6661. }
  6662. if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
  6663. {
  6664. $this->ihost = null;
  6665. }
  6666. if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
  6667. {
  6668. $this->port = null;
  6669. }
  6670. if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
  6671. {
  6672. $this->ipath = '';
  6673. }
  6674. if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
  6675. {
  6676. $this->iquery = null;
  6677. }
  6678. if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
  6679. {
  6680. $this->ifragment = null;
  6681. }
  6682. }
  6683. /**
  6684. * Check if the object represents a valid IRI. This needs to be done on each
  6685. * call as some things change depending on another part of the IRI.
  6686. *
  6687. * @return bool
  6688. */
  6689. public function is_valid()
  6690. {
  6691. $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
  6692. if ($this->ipath !== '' &&
  6693. (
  6694. $isauthority && (
  6695. $this->ipath[0] !== '/' ||
  6696. substr($this->ipath, 0, 2) === '//'
  6697. ) ||
  6698. (
  6699. $this->scheme === null &&
  6700. !$isauthority &&
  6701. strpos($this->ipath, ':') !== false &&
  6702. (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
  6703. )
  6704. )
  6705. )
  6706. {
  6707. return false;
  6708. }
  6709. return true;
  6710. }
  6711. /**
  6712. * Set the entire IRI. Returns true on success, false on failure (if there
  6713. * are any invalid characters).
  6714. *
  6715. * @param string $iri
  6716. * @return bool
  6717. */
  6718. public function set_iri($iri)
  6719. {
  6720. static $cache;
  6721. if (!$cache)
  6722. {
  6723. $cache = array();
  6724. }
  6725. if ($iri === null)
  6726. {
  6727. return true;
  6728. }
  6729. elseif (isset($cache[$iri]))
  6730. {
  6731. list($this->scheme,
  6732. $this->iuserinfo,
  6733. $this->ihost,
  6734. $this->port,
  6735. $this->ipath,
  6736. $this->iquery,
  6737. $this->ifragment,
  6738. $return) = $cache[$iri];
  6739. return $return;
  6740. }
  6741. else
  6742. {
  6743. $parsed = $this->parse_iri((string) $iri);
  6744. $return = $this->set_scheme($parsed['scheme'])
  6745. && $this->set_authority($parsed['authority'])
  6746. && $this->set_path($parsed['path'])
  6747. && $this->set_query($parsed['query'])
  6748. && $this->set_fragment($parsed['fragment']);
  6749. $cache[$iri] = array($this->scheme,
  6750. $this->iuserinfo,
  6751. $this->ihost,
  6752. $this->port,
  6753. $this->ipath,
  6754. $this->iquery,
  6755. $this->ifragment,
  6756. $return);
  6757. return $return;
  6758. }
  6759. }
  6760. /**
  6761. * Set the scheme. Returns true on success, false on failure (if there are
  6762. * any invalid characters).
  6763. *
  6764. * @param string $scheme
  6765. * @return bool
  6766. */
  6767. public function set_scheme($scheme)
  6768. {
  6769. if ($scheme === null)
  6770. {
  6771. $this->scheme = null;
  6772. }
  6773. elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
  6774. {
  6775. $this->scheme = null;
  6776. return false;
  6777. }
  6778. else
  6779. {
  6780. $this->scheme = strtolower($scheme);
  6781. }
  6782. return true;
  6783. }
  6784. /**
  6785. * Set the authority. Returns true on success, false on failure (if there are
  6786. * any invalid characters).
  6787. *
  6788. * @param string $authority
  6789. * @return bool
  6790. */
  6791. public function set_authority($authority)
  6792. {
  6793. static $cache;
  6794. if (!$cache)
  6795. $cache = array();
  6796. if ($authority === null)
  6797. {
  6798. $this->iuserinfo = null;
  6799. $this->ihost = null;
  6800. $this->port = null;
  6801. return true;
  6802. }
  6803. elseif (isset($cache[$authority]))
  6804. {
  6805. list($this->iuserinfo,
  6806. $this->ihost,
  6807. $this->port,
  6808. $return) = $cache[$authority];
  6809. return $return;
  6810. }
  6811. else
  6812. {
  6813. $remaining = $authority;
  6814. if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
  6815. {
  6816. $iuserinfo = substr($remaining, 0, $iuserinfo_end);
  6817. $remaining = substr($remaining, $iuserinfo_end + 1);
  6818. }
  6819. else
  6820. {
  6821. $iuserinfo = null;
  6822. }
  6823. if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
  6824. {
  6825. if (($port = substr($remaining, $port_start + 1)) === false)
  6826. {
  6827. $port = null;
  6828. }
  6829. $remaining = substr($remaining, 0, $port_start);
  6830. }
  6831. else
  6832. {
  6833. $port = null;
  6834. }
  6835. $return = $this->set_userinfo($iuserinfo) &&
  6836. $this->set_host($remaining) &&
  6837. $this->set_port($port);
  6838. $cache[$authority] = array($this->iuserinfo,
  6839. $this->ihost,
  6840. $this->port,
  6841. $return);
  6842. return $return;
  6843. }
  6844. }
  6845. /**
  6846. * Set the iuserinfo.
  6847. *
  6848. * @param string $iuserinfo
  6849. * @return bool
  6850. */
  6851. public function set_userinfo($iuserinfo)
  6852. {
  6853. if ($iuserinfo === null)
  6854. {
  6855. $this->iuserinfo = null;
  6856. }
  6857. else
  6858. {
  6859. $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
  6860. $this->scheme_normalization();
  6861. }
  6862. return true;
  6863. }
  6864. /**
  6865. * Set the ihost. Returns true on success, false on failure (if there are
  6866. * any invalid characters).
  6867. *
  6868. * @param string $ihost
  6869. * @return bool
  6870. */
  6871. public function set_host($ihost)
  6872. {
  6873. if ($ihost === null)
  6874. {
  6875. $this->ihost = null;
  6876. return true;
  6877. }
  6878. elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
  6879. {
  6880. if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
  6881. {
  6882. $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
  6883. }
  6884. else
  6885. {
  6886. $this->ihost = null;
  6887. return false;
  6888. }
  6889. }
  6890. else
  6891. {
  6892. $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
  6893. // Lowercase, but ignore pct-encoded sections (as they should
  6894. // remain uppercase). This must be done after the previous step
  6895. // as that can add unescaped characters.
  6896. $position = 0;
  6897. $strlen = strlen($ihost);
  6898. while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
  6899. {
  6900. if ($ihost[$position] === '%')
  6901. {
  6902. $position += 3;
  6903. }
  6904. else
  6905. {
  6906. $ihost[$position] = strtolower($ihost[$position]);
  6907. $position++;
  6908. }
  6909. }
  6910. $this->ihost = $ihost;
  6911. }
  6912. $this->scheme_normalization();
  6913. return true;
  6914. }
  6915. /**
  6916. * Set the port. Returns true on success, false on failure (if there are
  6917. * any invalid characters).
  6918. *
  6919. * @param string $port
  6920. * @return bool
  6921. */
  6922. public function set_port($port)
  6923. {
  6924. if ($port === null)
  6925. {
  6926. $this->port = null;
  6927. return true;
  6928. }
  6929. elseif (strspn($port, '0123456789') === strlen($port))
  6930. {
  6931. $this->port = (int) $port;
  6932. $this->scheme_normalization();
  6933. return true;
  6934. }
  6935. else
  6936. {
  6937. $this->port = null;
  6938. return false;
  6939. }
  6940. }
  6941. /**
  6942. * Set the ipath.
  6943. *
  6944. * @param string $ipath
  6945. * @return bool
  6946. */
  6947. public function set_path($ipath)
  6948. {
  6949. static $cache;
  6950. if (!$cache)
  6951. {
  6952. $cache = array();
  6953. }
  6954. $ipath = (string) $ipath;
  6955. if (isset($cache[$ipath]))
  6956. {
  6957. $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
  6958. }
  6959. else
  6960. {
  6961. $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
  6962. $removed = $this->remove_dot_segments($valid);
  6963. $cache[$ipath] = array($valid, $removed);
  6964. $this->ipath = ($this->scheme !== null) ? $removed : $valid;
  6965. }
  6966. $this->scheme_normalization();
  6967. return true;
  6968. }
  6969. /**
  6970. * Set the iquery.
  6971. *
  6972. * @param string $iquery
  6973. * @return bool
  6974. */
  6975. public function set_query($iquery)
  6976. {
  6977. if ($iquery === null)
  6978. {
  6979. $this->iquery = null;
  6980. }
  6981. else
  6982. {
  6983. $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
  6984. $this->scheme_normalization();
  6985. }
  6986. return true;
  6987. }
  6988. /**
  6989. * Set the ifragment.
  6990. *
  6991. * @param string $ifragment
  6992. * @return bool
  6993. */
  6994. public function set_fragment($ifragment)
  6995. {
  6996. if ($ifragment === null)
  6997. {
  6998. $this->ifragment = null;
  6999. }
  7000. else
  7001. {
  7002. $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
  7003. $this->scheme_normalization();
  7004. }
  7005. return true;
  7006. }
  7007. /**
  7008. * Convert an IRI to a URI (or parts thereof)
  7009. *
  7010. * @return string
  7011. */
  7012. public function to_uri($string)
  7013. {
  7014. static $non_ascii;
  7015. if (!$non_ascii)
  7016. {
  7017. $non_ascii = implode('', range("\x80", "\xFF"));
  7018. }
  7019. $position = 0;
  7020. $strlen = strlen($string);
  7021. while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
  7022. {
  7023. $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
  7024. $position += 3;
  7025. $strlen += 2;
  7026. }
  7027. return $string;
  7028. }
  7029. /**
  7030. * Get the complete IRI
  7031. *
  7032. * @return string
  7033. */
  7034. public function get_iri()
  7035. {
  7036. if (!$this->is_valid())
  7037. {
  7038. return false;
  7039. }
  7040. $iri = '';
  7041. if ($this->scheme !== null)
  7042. {
  7043. $iri .= $this->scheme . ':';
  7044. }
  7045. if (($iauthority = $this->get_iauthority()) !== null)
  7046. {
  7047. $iri .= '//' . $iauthority;
  7048. }
  7049. if ($this->ipath !== '')
  7050. {
  7051. $iri .= $this->ipath;
  7052. }
  7053. elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
  7054. {
  7055. $iri .= $this->normalization[$this->scheme]['ipath'];
  7056. }
  7057. if ($this->iquery !== null)
  7058. {
  7059. $iri .= '?' . $this->iquery;
  7060. }
  7061. if ($this->ifragment !== null)
  7062. {
  7063. $iri .= '#' . $this->ifragment;
  7064. }
  7065. return $iri;
  7066. }
  7067. /**
  7068. * Get the complete URI
  7069. *
  7070. * @return string
  7071. */
  7072. public function get_uri()
  7073. {
  7074. return $this->to_uri($this->get_iri());
  7075. }
  7076. /**
  7077. * Get the complete iauthority
  7078. *
  7079. * @return string
  7080. */
  7081. protected function get_iauthority()
  7082. {
  7083. if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
  7084. {
  7085. $iauthority = '';
  7086. if ($this->iuserinfo !== null)
  7087. {
  7088. $iauthority .= $this->iuserinfo . '@';
  7089. }
  7090. if ($this->ihost !== null)
  7091. {
  7092. $iauthority .= $this->ihost;
  7093. }
  7094. if ($this->port !== null)
  7095. {
  7096. $iauthority .= ':' . $this->port;
  7097. }
  7098. return $iauthority;
  7099. }
  7100. else
  7101. {
  7102. return null;
  7103. }
  7104. }
  7105. /**
  7106. * Get the complete authority
  7107. *
  7108. * @return string
  7109. */
  7110. protected function get_authority()
  7111. {
  7112. $iauthority = $this->get_iauthority();
  7113. if (is_string($iauthority))
  7114. return $this->to_uri($iauthority);
  7115. else
  7116. return $iauthority;
  7117. }
  7118. }
  7119. /**
  7120. * Handles `<media:credit>` as defined in Media RSS
  7121. *
  7122. * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
  7123. *
  7124. * This class can be overloaded with {@see SimplePie::set_credit_class()}
  7125. *
  7126. * @package SimplePie
  7127. * @subpackage API
  7128. */
  7129. class SimplePie_Credit
  7130. {
  7131. /**
  7132. * Credited role
  7133. *
  7134. * @var string
  7135. * @see get_role()
  7136. */
  7137. var $role;
  7138. /**
  7139. * Organizational scheme
  7140. *
  7141. * @var string
  7142. * @see get_scheme()
  7143. */
  7144. var $scheme;
  7145. /**
  7146. * Credited name
  7147. *
  7148. * @var string
  7149. * @see get_name()
  7150. */
  7151. var $name;
  7152. /**
  7153. * Constructor, used to input the data
  7154. *
  7155. * For documentation on all the parameters, see the corresponding
  7156. * properties and their accessors
  7157. */
  7158. public function __construct($role = null, $scheme = null, $name = null)
  7159. {
  7160. $this->role = $role;
  7161. $this->scheme = $scheme;
  7162. $this->name = $name;
  7163. }
  7164. /**
  7165. * String-ified version
  7166. *
  7167. * @return string
  7168. */
  7169. public function __toString()
  7170. {
  7171. // There is no $this->data here
  7172. return md5(serialize($this));
  7173. }
  7174. /**
  7175. * Get the role of the person receiving credit
  7176. *
  7177. * @return string|null
  7178. */
  7179. public function get_role()
  7180. {
  7181. if ($this->role !== null)
  7182. {
  7183. return $this->role;
  7184. }
  7185. else
  7186. {
  7187. return null;
  7188. }
  7189. }
  7190. /**
  7191. * Get the organizational scheme
  7192. *
  7193. * @return string|null
  7194. */
  7195. public function get_scheme()
  7196. {
  7197. if ($this->scheme !== null)
  7198. {
  7199. return $this->scheme;
  7200. }
  7201. else
  7202. {
  7203. return null;
  7204. }
  7205. }
  7206. /**
  7207. * Get the credited person/entity's name
  7208. *
  7209. * @return string|null
  7210. */
  7211. public function get_name()
  7212. {
  7213. if ($this->name !== null)
  7214. {
  7215. return $this->name;
  7216. }
  7217. else
  7218. {
  7219. return null;
  7220. }
  7221. }
  7222. }
  7223. /**
  7224. * Class to validate and to work with IPv6 addresses.
  7225. *
  7226. * @package SimplePie
  7227. * @subpackage HTTP
  7228. * @copyright 2003-2005 The PHP Group
  7229. * @license http://www.opensource.org/licenses/bsd-license.php
  7230. * @link http://pear.php.net/package/Net_IPv6
  7231. * @author Alexander Merz <alexander.merz@web.de>
  7232. * @author elfrink at introweb dot nl
  7233. * @author Josh Peck <jmp at joshpeck dot org>
  7234. * @author Geoffrey Sneddon <geoffers@gmail.com>
  7235. */
  7236. class SimplePie_Net_IPv6
  7237. {
  7238. /**
  7239. * Uncompresses an IPv6 address
  7240. *
  7241. * RFC 4291 allows you to compress concecutive zero pieces in an address to
  7242. * '::'. This method expects a valid IPv6 address and expands the '::' to
  7243. * the required number of zero pieces.
  7244. *
  7245. * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
  7246. * ::1 -> 0:0:0:0:0:0:0:1
  7247. *
  7248. * @author Alexander Merz <alexander.merz@web.de>
  7249. * @author elfrink at introweb dot nl
  7250. * @author Josh Peck <jmp at joshpeck dot org>
  7251. * @copyright 2003-2005 The PHP Group
  7252. * @license http://www.opensource.org/licenses/bsd-license.php
  7253. * @param string $ip An IPv6 address
  7254. * @return string The uncompressed IPv6 address
  7255. */
  7256. public static function uncompress($ip)
  7257. {
  7258. $c1 = -1;
  7259. $c2 = -1;
  7260. if (substr_count($ip, '::') === 1)
  7261. {
  7262. list($ip1, $ip2) = explode('::', $ip);
  7263. if ($ip1 === '')
  7264. {
  7265. $c1 = -1;
  7266. }
  7267. else
  7268. {
  7269. $c1 = substr_count($ip1, ':');
  7270. }
  7271. if ($ip2 === '')
  7272. {
  7273. $c2 = -1;
  7274. }
  7275. else
  7276. {
  7277. $c2 = substr_count($ip2, ':');
  7278. }
  7279. if (strpos($ip2, '.') !== false)
  7280. {
  7281. $c2++;
  7282. }
  7283. // ::
  7284. if ($c1 === -1 && $c2 === -1)
  7285. {
  7286. $ip = '0:0:0:0:0:0:0:0';
  7287. }
  7288. // ::xxx
  7289. else if ($c1 === -1)
  7290. {
  7291. $fill = str_repeat('0:', 7 - $c2);
  7292. $ip = str_replace('::', $fill, $ip);
  7293. }
  7294. // xxx::
  7295. else if ($c2 === -1)
  7296. {
  7297. $fill = str_repeat(':0', 7 - $c1);
  7298. $ip = str_replace('::', $fill, $ip);
  7299. }
  7300. // xxx::xxx
  7301. else
  7302. {
  7303. $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
  7304. $ip = str_replace('::', $fill, $ip);
  7305. }
  7306. }
  7307. return $ip;
  7308. }
  7309. /**
  7310. * Compresses an IPv6 address
  7311. *
  7312. * RFC 4291 allows you to compress concecutive zero pieces in an address to
  7313. * '::'. This method expects a valid IPv6 address and compresses consecutive
  7314. * zero pieces to '::'.
  7315. *
  7316. * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
  7317. * 0:0:0:0:0:0:0:1 -> ::1
  7318. *
  7319. * @see uncompress()
  7320. * @param string $ip An IPv6 address
  7321. * @return string The compressed IPv6 address
  7322. */
  7323. public static function compress($ip)
  7324. {
  7325. // Prepare the IP to be compressed
  7326. $ip = self::uncompress($ip);
  7327. $ip_parts = self::split_v6_v4($ip);
  7328. // Replace all leading zeros
  7329. $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
  7330. // Find bunches of zeros
  7331. if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
  7332. {
  7333. $max = 0;
  7334. $pos = null;
  7335. foreach ($matches[0] as $match)
  7336. {
  7337. if (strlen($match[0]) > $max)
  7338. {
  7339. $max = strlen($match[0]);
  7340. $pos = $match[1];
  7341. }
  7342. }
  7343. $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
  7344. }
  7345. if ($ip_parts[1] !== '')
  7346. {
  7347. return implode(':', $ip_parts);
  7348. }
  7349. else
  7350. {
  7351. return $ip_parts[0];
  7352. }
  7353. }
  7354. /**
  7355. * Splits an IPv6 address into the IPv6 and IPv4 representation parts
  7356. *
  7357. * RFC 4291 allows you to represent the last two parts of an IPv6 address
  7358. * using the standard IPv4 representation
  7359. *
  7360. * Example: 0:0:0:0:0:0:13.1.68.3
  7361. * 0:0:0:0:0:FFFF:129.144.52.38
  7362. *
  7363. * @param string $ip An IPv6 address
  7364. * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
  7365. */
  7366. private static function split_v6_v4($ip)
  7367. {
  7368. if (strpos($ip, '.') !== false)
  7369. {
  7370. $pos = strrpos($ip, ':');
  7371. $ipv6_part = substr($ip, 0, $pos);
  7372. $ipv4_part = substr($ip, $pos + 1);
  7373. return array($ipv6_part, $ipv4_part);
  7374. }
  7375. else
  7376. {
  7377. return array($ip, '');
  7378. }
  7379. }
  7380. /**
  7381. * Checks an IPv6 address
  7382. *
  7383. * Checks if the given IP is a valid IPv6 address
  7384. *
  7385. * @param string $ip An IPv6 address
  7386. * @return bool true if $ip is a valid IPv6 address
  7387. */
  7388. public static function check_ipv6($ip)
  7389. {
  7390. $ip = self::uncompress($ip);
  7391. list($ipv6, $ipv4) = self::split_v6_v4($ip);
  7392. $ipv6 = explode(':', $ipv6);
  7393. $ipv4 = explode('.', $ipv4);
  7394. if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
  7395. {
  7396. foreach ($ipv6 as $ipv6_part)
  7397. {
  7398. // The section can't be empty
  7399. if ($ipv6_part === '')
  7400. return false;
  7401. // Nor can it be over four characters
  7402. if (strlen($ipv6_part) > 4)
  7403. return false;
  7404. // Remove leading zeros (this is safe because of the above)
  7405. $ipv6_part = ltrim($ipv6_part, '0');
  7406. if ($ipv6_part === '')
  7407. $ipv6_part = '0';
  7408. // Check the value is valid
  7409. $value = hexdec($ipv6_part);
  7410. if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
  7411. return false;
  7412. }
  7413. if (count($ipv4) === 4)
  7414. {
  7415. foreach ($ipv4 as $ipv4_part)
  7416. {
  7417. $value = (int) $ipv4_part;
  7418. if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
  7419. return false;
  7420. }
  7421. }
  7422. return true;
  7423. }
  7424. else
  7425. {
  7426. return false;
  7427. }
  7428. }
  7429. /**
  7430. * Checks if the given IP is a valid IPv6 address
  7431. *
  7432. * @codeCoverageIgnore
  7433. * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
  7434. * @see check_ipv6
  7435. * @param string $ip An IPv6 address
  7436. * @return bool true if $ip is a valid IPv6 address
  7437. */
  7438. public static function checkIPv6($ip)
  7439. {
  7440. return self::check_ipv6($ip);
  7441. }
  7442. }
  7443. /**
  7444. * Manages all category-related data
  7445. *
  7446. * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
  7447. *
  7448. * This class can be overloaded with {@see SimplePie::set_category_class()}
  7449. *
  7450. * @package SimplePie
  7451. * @subpackage API
  7452. */
  7453. class SimplePie_Category
  7454. {
  7455. /**
  7456. * Category identifier
  7457. *
  7458. * @var string
  7459. * @see get_term
  7460. */
  7461. var $term;
  7462. /**
  7463. * Categorization scheme identifier
  7464. *
  7465. * @var string
  7466. * @see get_scheme()
  7467. */
  7468. var $scheme;
  7469. /**
  7470. * Human readable label
  7471. *
  7472. * @var string
  7473. * @see get_label()
  7474. */
  7475. var $label;
  7476. /**
  7477. * Constructor, used to input the data
  7478. *
  7479. * @param string $term
  7480. * @param string $scheme
  7481. * @param string $label
  7482. */
  7483. public function __construct($term = null, $scheme = null, $label = null)
  7484. {
  7485. $this->term = $term;
  7486. $this->scheme = $scheme;
  7487. $this->label = $label;
  7488. }
  7489. /**
  7490. * String-ified version
  7491. *
  7492. * @return string
  7493. */
  7494. public function __toString()
  7495. {
  7496. // There is no $this->data here
  7497. return md5(serialize($this));
  7498. }
  7499. /**
  7500. * Get the category identifier
  7501. *
  7502. * @return string|null
  7503. */
  7504. public function get_term()
  7505. {
  7506. if ($this->term !== null)
  7507. {
  7508. return $this->term;
  7509. }
  7510. else
  7511. {
  7512. return null;
  7513. }
  7514. }
  7515. /**
  7516. * Get the categorization scheme identifier
  7517. *
  7518. * @return string|null
  7519. */
  7520. public function get_scheme()
  7521. {
  7522. if ($this->scheme !== null)
  7523. {
  7524. return $this->scheme;
  7525. }
  7526. else
  7527. {
  7528. return null;
  7529. }
  7530. }
  7531. /**
  7532. * Get the human readable label
  7533. *
  7534. * @return string|null
  7535. */
  7536. public function get_label()
  7537. {
  7538. if ($this->label !== null)
  7539. {
  7540. return $this->label;
  7541. }
  7542. else
  7543. {
  7544. return $this->get_term();
  7545. }
  7546. }
  7547. }
  7548. /**
  7549. * Handles `<media:text>` captions as defined in Media RSS.
  7550. *
  7551. * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
  7552. *
  7553. * This class can be overloaded with {@see SimplePie::set_caption_class()}
  7554. *
  7555. * @package SimplePie
  7556. * @subpackage API
  7557. */
  7558. class SimplePie_Caption
  7559. {
  7560. /**
  7561. * Content type
  7562. *
  7563. * @var string
  7564. * @see get_type()
  7565. */
  7566. var $type;
  7567. /**
  7568. * Language
  7569. *
  7570. * @var string
  7571. * @see get_language()
  7572. */
  7573. var $lang;
  7574. /**
  7575. * Start time
  7576. *
  7577. * @var string
  7578. * @see get_starttime()
  7579. */
  7580. var $startTime;
  7581. /**
  7582. * End time
  7583. *
  7584. * @var string
  7585. * @see get_endtime()
  7586. */
  7587. var $endTime;
  7588. /**
  7589. * Caption text
  7590. *
  7591. * @var string
  7592. * @see get_text()
  7593. */
  7594. var $text;
  7595. /**
  7596. * Constructor, used to input the data
  7597. *
  7598. * For documentation on all the parameters, see the corresponding
  7599. * properties and their accessors
  7600. */
  7601. public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
  7602. {
  7603. $this->type = $type;
  7604. $this->lang = $lang;
  7605. $this->startTime = $startTime;
  7606. $this->endTime = $endTime;
  7607. $this->text = $text;
  7608. }
  7609. /**
  7610. * String-ified version
  7611. *
  7612. * @return string
  7613. */
  7614. public function __toString()
  7615. {
  7616. // There is no $this->data here
  7617. return md5(serialize($this));
  7618. }
  7619. /**
  7620. * Get the end time
  7621. *
  7622. * @return string|null Time in the format 'hh:mm:ss.SSS'
  7623. */
  7624. public function get_endtime()
  7625. {
  7626. if ($this->endTime !== null)
  7627. {
  7628. return $this->endTime;
  7629. }
  7630. else
  7631. {
  7632. return null;
  7633. }
  7634. }
  7635. /**
  7636. * Get the language
  7637. *
  7638. * @link http://tools.ietf.org/html/rfc3066
  7639. * @return string|null Language code as per RFC 3066
  7640. */
  7641. public function get_language()
  7642. {
  7643. if ($this->lang !== null)
  7644. {
  7645. return $this->lang;
  7646. }
  7647. else
  7648. {
  7649. return null;
  7650. }
  7651. }
  7652. /**
  7653. * Get the start time
  7654. *
  7655. * @return string|null Time in the format 'hh:mm:ss.SSS'
  7656. */
  7657. public function get_starttime()
  7658. {
  7659. if ($this->startTime !== null)
  7660. {
  7661. return $this->startTime;
  7662. }
  7663. else
  7664. {
  7665. return null;
  7666. }
  7667. }
  7668. /**
  7669. * Get the text of the caption
  7670. *
  7671. * @return string|null
  7672. */
  7673. public function get_text()
  7674. {
  7675. if ($this->text !== null)
  7676. {
  7677. return $this->text;
  7678. }
  7679. else
  7680. {
  7681. return null;
  7682. }
  7683. }
  7684. /**
  7685. * Get the content type (not MIME type)
  7686. *
  7687. * @return string|null Either 'text' or 'html'
  7688. */
  7689. public function get_type()
  7690. {
  7691. if ($this->type !== null)
  7692. {
  7693. return $this->type;
  7694. }
  7695. else
  7696. {
  7697. return null;
  7698. }
  7699. }
  7700. }
  7701. /**
  7702. * Date Parser
  7703. *
  7704. * @package SimplePie
  7705. * @subpackage Parsing
  7706. */
  7707. class SimplePie_Parse_Date
  7708. {
  7709. /**
  7710. * Input data
  7711. *
  7712. * @access protected
  7713. * @var string
  7714. */
  7715. var $date;
  7716. /**
  7717. * List of days, calendar day name => ordinal day number in the week
  7718. *
  7719. * @access protected
  7720. * @var array
  7721. */
  7722. var $day = array(
  7723. // English
  7724. 'mon' => 1,
  7725. 'monday' => 1,
  7726. 'tue' => 2,
  7727. 'tuesday' => 2,
  7728. 'wed' => 3,
  7729. 'wednesday' => 3,
  7730. 'thu' => 4,
  7731. 'thursday' => 4,
  7732. 'fri' => 5,
  7733. 'friday' => 5,
  7734. 'sat' => 6,
  7735. 'saturday' => 6,
  7736. 'sun' => 7,
  7737. 'sunday' => 7,
  7738. // Dutch
  7739. 'maandag' => 1,
  7740. 'dinsdag' => 2,
  7741. 'woensdag' => 3,
  7742. 'donderdag' => 4,
  7743. 'vrijdag' => 5,
  7744. 'zaterdag' => 6,
  7745. 'zondag' => 7,
  7746. // French
  7747. 'lundi' => 1,
  7748. 'mardi' => 2,
  7749. 'mercredi' => 3,
  7750. 'jeudi' => 4,
  7751. 'vendredi' => 5,
  7752. 'samedi' => 6,
  7753. 'dimanche' => 7,
  7754. // German
  7755. 'montag' => 1,
  7756. 'dienstag' => 2,
  7757. 'mittwoch' => 3,
  7758. 'donnerstag' => 4,
  7759. 'freitag' => 5,
  7760. 'samstag' => 6,
  7761. 'sonnabend' => 6,
  7762. 'sonntag' => 7,
  7763. // Italian
  7764. 'lunedì' => 1,
  7765. 'martedì' => 2,
  7766. 'mercoledì' => 3,
  7767. 'giovedì' => 4,
  7768. 'venerdì' => 5,
  7769. 'sabato' => 6,
  7770. 'domenica' => 7,
  7771. // Spanish
  7772. 'lunes' => 1,
  7773. 'martes' => 2,
  7774. 'miércoles' => 3,
  7775. 'jueves' => 4,
  7776. 'viernes' => 5,
  7777. 'sábado' => 6,
  7778. 'domingo' => 7,
  7779. // Finnish
  7780. 'maanantai' => 1,
  7781. 'tiistai' => 2,
  7782. 'keskiviikko' => 3,
  7783. 'torstai' => 4,
  7784. 'perjantai' => 5,
  7785. 'lauantai' => 6,
  7786. 'sunnuntai' => 7,
  7787. // Hungarian
  7788. 'hétfő' => 1,
  7789. 'kedd' => 2,
  7790. 'szerda' => 3,
  7791. 'csütörtok' => 4,
  7792. 'péntek' => 5,
  7793. 'szombat' => 6,
  7794. 'vasárnap' => 7,
  7795. // Greek
  7796. 'Δευ' => 1,
  7797. 'Τρι' => 2,
  7798. 'Τετ' => 3,
  7799. 'Πεμ' => 4,
  7800. 'Παρ' => 5,
  7801. 'Σαβ' => 6,
  7802. 'Κυρ' => 7,
  7803. );
  7804. /**
  7805. * List of months, calendar month name => calendar month number
  7806. *
  7807. * @access protected
  7808. * @var array
  7809. */
  7810. var $month = array(
  7811. // English
  7812. 'jan' => 1,
  7813. 'january' => 1,
  7814. 'feb' => 2,
  7815. 'february' => 2,
  7816. 'mar' => 3,
  7817. 'march' => 3,
  7818. 'apr' => 4,
  7819. 'april' => 4,
  7820. 'may' => 5,
  7821. // No long form of May
  7822. 'jun' => 6,
  7823. 'june' => 6,
  7824. 'jul' => 7,
  7825. 'july' => 7,
  7826. 'aug' => 8,
  7827. 'august' => 8,
  7828. 'sep' => 9,
  7829. 'september' => 8,
  7830. 'oct' => 10,
  7831. 'october' => 10,
  7832. 'nov' => 11,
  7833. 'november' => 11,
  7834. 'dec' => 12,
  7835. 'december' => 12,
  7836. // Dutch
  7837. 'januari' => 1,
  7838. 'februari' => 2,
  7839. 'maart' => 3,
  7840. 'april' => 4,
  7841. 'mei' => 5,
  7842. 'juni' => 6,
  7843. 'juli' => 7,
  7844. 'augustus' => 8,
  7845. 'september' => 9,
  7846. 'oktober' => 10,
  7847. 'november' => 11,
  7848. 'december' => 12,
  7849. // French
  7850. 'janvier' => 1,
  7851. 'février' => 2,
  7852. 'mars' => 3,
  7853. 'avril' => 4,
  7854. 'mai' => 5,
  7855. 'juin' => 6,
  7856. 'juillet' => 7,
  7857. 'août' => 8,
  7858. 'septembre' => 9,
  7859. 'octobre' => 10,
  7860. 'novembre' => 11,
  7861. 'décembre' => 12,
  7862. // German
  7863. 'januar' => 1,
  7864. 'februar' => 2,
  7865. 'märz' => 3,
  7866. 'april' => 4,
  7867. 'mai' => 5,
  7868. 'juni' => 6,
  7869. 'juli' => 7,
  7870. 'august' => 8,
  7871. 'september' => 9,
  7872. 'oktober' => 10,
  7873. 'november' => 11,
  7874. 'dezember' => 12,
  7875. // Italian
  7876. 'gennaio' => 1,
  7877. 'febbraio' => 2,
  7878. 'marzo' => 3,
  7879. 'aprile' => 4,
  7880. 'maggio' => 5,
  7881. 'giugno' => 6,
  7882. 'luglio' => 7,
  7883. 'agosto' => 8,
  7884. 'settembre' => 9,
  7885. 'ottobre' => 10,
  7886. 'novembre' => 11,
  7887. 'dicembre' => 12,
  7888. // Spanish
  7889. 'enero' => 1,
  7890. 'febrero' => 2,
  7891. 'marzo' => 3,
  7892. 'abril' => 4,
  7893. 'mayo' => 5,
  7894. 'junio' => 6,
  7895. 'julio' => 7,
  7896. 'agosto' => 8,
  7897. 'septiembre' => 9,
  7898. 'setiembre' => 9,
  7899. 'octubre' => 10,
  7900. 'noviembre' => 11,
  7901. 'diciembre' => 12,
  7902. // Finnish
  7903. 'tammikuu' => 1,
  7904. 'helmikuu' => 2,
  7905. 'maaliskuu' => 3,
  7906. 'huhtikuu' => 4,
  7907. 'toukokuu' => 5,
  7908. 'kesäkuu' => 6,
  7909. 'heinäkuu' => 7,
  7910. 'elokuu' => 8,
  7911. 'suuskuu' => 9,
  7912. 'lokakuu' => 10,
  7913. 'marras' => 11,
  7914. 'joulukuu' => 12,
  7915. // Hungarian
  7916. 'január' => 1,
  7917. 'február' => 2,
  7918. 'március' => 3,
  7919. 'április' => 4,
  7920. 'május' => 5,
  7921. 'június' => 6,
  7922. 'július' => 7,
  7923. 'augusztus' => 8,
  7924. 'szeptember' => 9,
  7925. 'október' => 10,
  7926. 'november' => 11,
  7927. 'december' => 12,
  7928. // Greek
  7929. 'Ιαν' => 1,
  7930. 'Φεβ' => 2,
  7931. 'Μάώ' => 3,
  7932. 'Μαώ' => 3,
  7933. 'Απρ' => 4,
  7934. 'Μάι' => 5,
  7935. 'Μαϊ' => 5,
  7936. 'Μαι' => 5,
  7937. 'Ιούν' => 6,
  7938. 'Ιον' => 6,
  7939. 'Ιούλ' => 7,
  7940. 'Ιολ' => 7,
  7941. 'Αύγ' => 8,
  7942. 'Αυγ' => 8,
  7943. 'Σεπ' => 9,
  7944. 'Οκτ' => 10,
  7945. 'Νοέ' => 11,
  7946. 'Δεκ' => 12,
  7947. );
  7948. /**
  7949. * List of timezones, abbreviation => offset from UTC
  7950. *
  7951. * @access protected
  7952. * @var array
  7953. */
  7954. var $timezone = array(
  7955. 'ACDT' => 37800,
  7956. 'ACIT' => 28800,
  7957. 'ACST' => 34200,
  7958. 'ACT' => -18000,
  7959. 'ACWDT' => 35100,
  7960. 'ACWST' => 31500,
  7961. 'AEDT' => 39600,
  7962. 'AEST' => 36000,
  7963. 'AFT' => 16200,
  7964. 'AKDT' => -28800,
  7965. 'AKST' => -32400,
  7966. 'AMDT' => 18000,
  7967. 'AMT' => -14400,
  7968. 'ANAST' => 46800,
  7969. 'ANAT' => 43200,
  7970. 'ART' => -10800,
  7971. 'AZOST' => -3600,
  7972. 'AZST' => 18000,
  7973. 'AZT' => 14400,
  7974. 'BIOT' => 21600,
  7975. 'BIT' => -43200,
  7976. 'BOT' => -14400,
  7977. 'BRST' => -7200,
  7978. 'BRT' => -10800,
  7979. 'BST' => 3600,
  7980. 'BTT' => 21600,
  7981. 'CAST' => 18000,
  7982. 'CAT' => 7200,
  7983. 'CCT' => 23400,
  7984. 'CDT' => -18000,
  7985. 'CEDT' => 7200,
  7986. 'CET' => 3600,
  7987. 'CGST' => -7200,
  7988. 'CGT' => -10800,
  7989. 'CHADT' => 49500,
  7990. 'CHAST' => 45900,
  7991. 'CIST' => -28800,
  7992. 'CKT' => -36000,
  7993. 'CLDT' => -10800,
  7994. 'CLST' => -14400,
  7995. 'COT' => -18000,
  7996. 'CST' => -21600,
  7997. 'CVT' => -3600,
  7998. 'CXT' => 25200,
  7999. 'DAVT' => 25200,
  8000. 'DTAT' => 36000,
  8001. 'EADT' => -18000,
  8002. 'EAST' => -21600,
  8003. 'EAT' => 10800,
  8004. 'ECT' => -18000,
  8005. 'EDT' => -14400,
  8006. 'EEST' => 10800,
  8007. 'EET' => 7200,
  8008. 'EGT' => -3600,
  8009. 'EKST' => 21600,
  8010. 'EST' => -18000,
  8011. 'FJT' => 43200,
  8012. 'FKDT' => -10800,
  8013. 'FKST' => -14400,
  8014. 'FNT' => -7200,
  8015. 'GALT' => -21600,
  8016. 'GEDT' => 14400,
  8017. 'GEST' => 10800,
  8018. 'GFT' => -10800,
  8019. 'GILT' => 43200,
  8020. 'GIT' => -32400,
  8021. 'GST' => 14400,
  8022. 'GST' => -7200,
  8023. 'GYT' => -14400,
  8024. 'HAA' => -10800,
  8025. 'HAC' => -18000,
  8026. 'HADT' => -32400,
  8027. 'HAE' => -14400,
  8028. 'HAP' => -25200,
  8029. 'HAR' => -21600,
  8030. 'HAST' => -36000,
  8031. 'HAT' => -9000,
  8032. 'HAY' => -28800,
  8033. 'HKST' => 28800,
  8034. 'HMT' => 18000,
  8035. 'HNA' => -14400,
  8036. 'HNC' => -21600,
  8037. 'HNE' => -18000,
  8038. 'HNP' => -28800,
  8039. 'HNR' => -25200,
  8040. 'HNT' => -12600,
  8041. 'HNY' => -32400,
  8042. 'IRDT' => 16200,
  8043. 'IRKST' => 32400,
  8044. 'IRKT' => 28800,
  8045. 'IRST' => 12600,
  8046. 'JFDT' => -10800,
  8047. 'JFST' => -14400,
  8048. 'JST' => 32400,
  8049. 'KGST' => 21600,
  8050. 'KGT' => 18000,
  8051. 'KOST' => 39600,
  8052. 'KOVST' => 28800,
  8053. 'KOVT' => 25200,
  8054. 'KRAST' => 28800,
  8055. 'KRAT' => 25200,
  8056. 'KST' => 32400,
  8057. 'LHDT' => 39600,
  8058. 'LHST' => 37800,
  8059. 'LINT' => 50400,
  8060. 'LKT' => 21600,
  8061. 'MAGST' => 43200,
  8062. 'MAGT' => 39600,
  8063. 'MAWT' => 21600,
  8064. 'MDT' => -21600,
  8065. 'MESZ' => 7200,
  8066. 'MEZ' => 3600,
  8067. 'MHT' => 43200,
  8068. 'MIT' => -34200,
  8069. 'MNST' => 32400,
  8070. 'MSDT' => 14400,
  8071. 'MSST' => 10800,
  8072. 'MST' => -25200,
  8073. 'MUT' => 14400,
  8074. 'MVT' => 18000,
  8075. 'MYT' => 28800,
  8076. 'NCT' => 39600,
  8077. 'NDT' => -9000,
  8078. 'NFT' => 41400,
  8079. 'NMIT' => 36000,
  8080. 'NOVST' => 25200,
  8081. 'NOVT' => 21600,
  8082. 'NPT' => 20700,
  8083. 'NRT' => 43200,
  8084. 'NST' => -12600,
  8085. 'NUT' => -39600,
  8086. 'NZDT' => 46800,
  8087. 'NZST' => 43200,
  8088. 'OMSST' => 25200,
  8089. 'OMST' => 21600,
  8090. 'PDT' => -25200,
  8091. 'PET' => -18000,
  8092. 'PETST' => 46800,
  8093. 'PETT' => 43200,
  8094. 'PGT' => 36000,
  8095. 'PHOT' => 46800,
  8096. 'PHT' => 28800,
  8097. 'PKT' => 18000,
  8098. 'PMDT' => -7200,
  8099. 'PMST' => -10800,
  8100. 'PONT' => 39600,
  8101. 'PST' => -28800,
  8102. 'PWT' => 32400,
  8103. 'PYST' => -10800,
  8104. 'PYT' => -14400,
  8105. 'RET' => 14400,
  8106. 'ROTT' => -10800,
  8107. 'SAMST' => 18000,
  8108. 'SAMT' => 14400,
  8109. 'SAST' => 7200,
  8110. 'SBT' => 39600,
  8111. 'SCDT' => 46800,
  8112. 'SCST' => 43200,
  8113. 'SCT' => 14400,
  8114. 'SEST' => 3600,
  8115. 'SGT' => 28800,
  8116. 'SIT' => 28800,
  8117. 'SRT' => -10800,
  8118. 'SST' => -39600,
  8119. 'SYST' => 10800,
  8120. 'SYT' => 7200,
  8121. 'TFT' => 18000,
  8122. 'THAT' => -36000,
  8123. 'TJT' => 18000,
  8124. 'TKT' => -36000,
  8125. 'TMT' => 18000,
  8126. 'TOT' => 46800,
  8127. 'TPT' => 32400,
  8128. 'TRUT' => 36000,
  8129. 'TVT' => 43200,
  8130. 'TWT' => 28800,
  8131. 'UYST' => -7200,
  8132. 'UYT' => -10800,
  8133. 'UZT' => 18000,
  8134. 'VET' => -14400,
  8135. 'VLAST' => 39600,
  8136. 'VLAT' => 36000,
  8137. 'VOST' => 21600,
  8138. 'VUT' => 39600,
  8139. 'WAST' => 7200,
  8140. 'WAT' => 3600,
  8141. 'WDT' => 32400,
  8142. 'WEST' => 3600,
  8143. 'WFT' => 43200,
  8144. 'WIB' => 25200,
  8145. 'WIT' => 32400,
  8146. 'WITA' => 28800,
  8147. 'WKST' => 18000,
  8148. 'WST' => 28800,
  8149. 'YAKST' => 36000,
  8150. 'YAKT' => 32400,
  8151. 'YAPT' => 36000,
  8152. 'YEKST' => 21600,
  8153. 'YEKT' => 18000,
  8154. );
  8155. /**
  8156. * Cached PCRE for SimplePie_Parse_Date::$day
  8157. *
  8158. * @access protected
  8159. * @var string
  8160. */
  8161. var $day_pcre;
  8162. /**
  8163. * Cached PCRE for SimplePie_Parse_Date::$month
  8164. *
  8165. * @access protected
  8166. * @var string
  8167. */
  8168. var $month_pcre;
  8169. /**
  8170. * Array of user-added callback methods
  8171. *
  8172. * @access private
  8173. * @var array
  8174. */
  8175. var $built_in = array();
  8176. /**
  8177. * Array of user-added callback methods
  8178. *
  8179. * @access private
  8180. * @var array
  8181. */
  8182. var $user = array();
  8183. /**
  8184. * Create new SimplePie_Parse_Date object, and set self::day_pcre,
  8185. * self::month_pcre, and self::built_in
  8186. *
  8187. * @access private
  8188. */
  8189. public function __construct()
  8190. {
  8191. $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
  8192. $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
  8193. static $cache;
  8194. if (!isset($cache[get_class($this)]))
  8195. {
  8196. $all_methods = get_class_methods($this);
  8197. foreach ($all_methods as $method)
  8198. {
  8199. if (strtolower(substr($method, 0, 5)) === 'date_')
  8200. {
  8201. $cache[get_class($this)][] = $method;
  8202. }
  8203. }
  8204. }
  8205. foreach ($cache[get_class($this)] as $method)
  8206. {
  8207. $this->built_in[] = $method;
  8208. }
  8209. }
  8210. /**
  8211. * Get the object
  8212. *
  8213. * @access public
  8214. */
  8215. public static function get()
  8216. {
  8217. static $object;
  8218. if (!$object)
  8219. {
  8220. $object = new SimplePie_Parse_Date;
  8221. }
  8222. return $object;
  8223. }
  8224. /**
  8225. * Parse a date
  8226. *
  8227. * @final
  8228. * @access public
  8229. * @param string $date Date to parse
  8230. * @return int Timestamp corresponding to date string, or false on failure
  8231. */
  8232. public function parse($date)
  8233. {
  8234. foreach ($this->user as $method)
  8235. {
  8236. if (($returned = call_user_func($method, $date)) !== false)
  8237. {
  8238. return $returned;
  8239. }
  8240. }
  8241. foreach ($this->built_in as $method)
  8242. {
  8243. if (($returned = call_user_func(array($this, $method), $date)) !== false)
  8244. {
  8245. return $returned;
  8246. }
  8247. }
  8248. return false;
  8249. }
  8250. /**
  8251. * Add a callback method to parse a date
  8252. *
  8253. * @final
  8254. * @access public
  8255. * @param callback $callback
  8256. */
  8257. public function add_callback($callback)
  8258. {
  8259. if (is_callable($callback))
  8260. {
  8261. $this->user[] = $callback;
  8262. }
  8263. else
  8264. {
  8265. trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
  8266. }
  8267. }
  8268. /**
  8269. * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
  8270. * well as allowing any of upper or lower case "T", horizontal tabs, or
  8271. * spaces to be used as the time seperator (including more than one))
  8272. *
  8273. * @access protected
  8274. * @return int Timestamp
  8275. */
  8276. public function date_w3cdtf($date)
  8277. {
  8278. static $pcre;
  8279. if (!$pcre)
  8280. {
  8281. $year = '([0-9]{4})';
  8282. $month = $day = $hour = $minute = $second = '([0-9]{2})';
  8283. $decimal = '([0-9]*)';
  8284. $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
  8285. $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
  8286. }
  8287. if (preg_match($pcre, $date, $match))
  8288. {
  8289. /*
  8290. Capturing subpatterns:
  8291. 1: Year
  8292. 2: Month
  8293. 3: Day
  8294. 4: Hour
  8295. 5: Minute
  8296. 6: Second
  8297. 7: Decimal fraction of a second
  8298. 8: Zulu
  8299. 9: Timezone ±
  8300. 10: Timezone hours
  8301. 11: Timezone minutes
  8302. */
  8303. // Fill in empty matches
  8304. for ($i = count($match); $i <= 3; $i++)
  8305. {
  8306. $match[$i] = '1';
  8307. }
  8308. for ($i = count($match); $i <= 7; $i++)
  8309. {
  8310. $match[$i] = '0';
  8311. }
  8312. // Numeric timezone
  8313. if (isset($match[9]) && $match[9] !== '')
  8314. {
  8315. $timezone = $match[10] * 3600;
  8316. $timezone += $match[11] * 60;
  8317. if ($match[9] === '-')
  8318. {
  8319. $timezone = 0 - $timezone;
  8320. }
  8321. }
  8322. else
  8323. {
  8324. $timezone = 0;
  8325. }
  8326. // Convert the number of seconds to an integer, taking decimals into account
  8327. $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
  8328. return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
  8329. }
  8330. else
  8331. {
  8332. return false;
  8333. }
  8334. }
  8335. /**
  8336. * Remove RFC822 comments
  8337. *
  8338. * @access protected
  8339. * @param string $data Data to strip comments from
  8340. * @return string Comment stripped string
  8341. */
  8342. public function remove_rfc2822_comments($string)
  8343. {
  8344. $string = (string) $string;
  8345. $position = 0;
  8346. $length = strlen($string);
  8347. $depth = 0;
  8348. $output = '';
  8349. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  8350. {
  8351. $output .= substr($string, $position, $pos - $position);
  8352. $position = $pos + 1;
  8353. if ($string[$pos - 1] !== '\\')
  8354. {
  8355. $depth++;
  8356. while ($depth && $position < $length)
  8357. {
  8358. $position += strcspn($string, '()', $position);
  8359. if ($string[$position - 1] === '\\')
  8360. {
  8361. $position++;
  8362. continue;
  8363. }
  8364. elseif (isset($string[$position]))
  8365. {
  8366. switch ($string[$position])
  8367. {
  8368. case '(':
  8369. $depth++;
  8370. break;
  8371. case ')':
  8372. $depth--;
  8373. break;
  8374. }
  8375. $position++;
  8376. }
  8377. else
  8378. {
  8379. break;
  8380. }
  8381. }
  8382. }
  8383. else
  8384. {
  8385. $output .= '(';
  8386. }
  8387. }
  8388. $output .= substr($string, $position);
  8389. return $output;
  8390. }
  8391. /**
  8392. * Parse RFC2822's date format
  8393. *
  8394. * @access protected
  8395. * @return int Timestamp
  8396. */
  8397. public function date_rfc2822($date)
  8398. {
  8399. static $pcre;
  8400. if (!$pcre)
  8401. {
  8402. $wsp = '[\x09\x20]';
  8403. $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
  8404. $optional_fws = $fws . '?';
  8405. $day_name = $this->day_pcre;
  8406. $month = $this->month_pcre;
  8407. $day = '([0-9]{1,2})';
  8408. $hour = $minute = $second = '([0-9]{2})';
  8409. $year = '([0-9]{2,4})';
  8410. $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
  8411. $character_zone = '([A-Z]{1,5})';
  8412. $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
  8413. $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';
  8414. }
  8415. if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
  8416. {
  8417. /*
  8418. Capturing subpatterns:
  8419. 1: Day name
  8420. 2: Day
  8421. 3: Month
  8422. 4: Year
  8423. 5: Hour
  8424. 6: Minute
  8425. 7: Second
  8426. 8: Timezone ±
  8427. 9: Timezone hours
  8428. 10: Timezone minutes
  8429. 11: Alphabetic timezone
  8430. */
  8431. // Find the month number
  8432. $month = $this->month[strtolower($match[3])];
  8433. // Numeric timezone
  8434. if ($match[8] !== '')
  8435. {
  8436. $timezone = $match[9] * 3600;
  8437. $timezone += $match[10] * 60;
  8438. if ($match[8] === '-')
  8439. {
  8440. $timezone = 0 - $timezone;
  8441. }
  8442. }
  8443. // Character timezone
  8444. elseif (isset($this->timezone[strtoupper($match[11])]))
  8445. {
  8446. $timezone = $this->timezone[strtoupper($match[11])];
  8447. }
  8448. // Assume everything else to be -0000
  8449. else
  8450. {
  8451. $timezone = 0;
  8452. }
  8453. // Deal with 2/3 digit years
  8454. if ($match[4] < 50)
  8455. {
  8456. $match[4] += 2000;
  8457. }
  8458. elseif ($match[4] < 1000)
  8459. {
  8460. $match[4] += 1900;
  8461. }
  8462. // Second is optional, if it is empty set it to zero
  8463. if ($match[7] !== '')
  8464. {
  8465. $second = $match[7];
  8466. }
  8467. else
  8468. {
  8469. $second = 0;
  8470. }
  8471. return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
  8472. }
  8473. else
  8474. {
  8475. return false;
  8476. }
  8477. }
  8478. /**
  8479. * Parse RFC850's date format
  8480. *
  8481. * @access protected
  8482. * @return int Timestamp
  8483. */
  8484. public function date_rfc850($date)
  8485. {
  8486. static $pcre;
  8487. if (!$pcre)
  8488. {
  8489. $space = '[\x09\x20]+';
  8490. $day_name = $this->day_pcre;
  8491. $month = $this->month_pcre;
  8492. $day = '([0-9]{1,2})';
  8493. $year = $hour = $minute = $second = '([0-9]{2})';
  8494. $zone = '([A-Z]{1,5})';
  8495. $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
  8496. }
  8497. if (preg_match($pcre, $date, $match))
  8498. {
  8499. /*
  8500. Capturing subpatterns:
  8501. 1: Day name
  8502. 2: Day
  8503. 3: Month
  8504. 4: Year
  8505. 5: Hour
  8506. 6: Minute
  8507. 7: Second
  8508. 8: Timezone
  8509. */
  8510. // Month
  8511. $month = $this->month[strtolower($match[3])];
  8512. // Character timezone
  8513. if (isset($this->timezone[strtoupper($match[8])]))
  8514. {
  8515. $timezone = $this->timezone[strtoupper($match[8])];
  8516. }
  8517. // Assume everything else to be -0000
  8518. else
  8519. {
  8520. $timezone = 0;
  8521. }
  8522. // Deal with 2 digit year
  8523. if ($match[4] < 50)
  8524. {
  8525. $match[4] += 2000;
  8526. }
  8527. else
  8528. {
  8529. $match[4] += 1900;
  8530. }
  8531. return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
  8532. }
  8533. else
  8534. {
  8535. return false;
  8536. }
  8537. }
  8538. /**
  8539. * Parse C99's asctime()'s date format
  8540. *
  8541. * @access protected
  8542. * @return int Timestamp
  8543. */
  8544. public function date_asctime($date)
  8545. {
  8546. static $pcre;
  8547. if (!$pcre)
  8548. {
  8549. $space = '[\x09\x20]+';
  8550. $wday_name = $this->day_pcre;
  8551. $mon_name = $this->month_pcre;
  8552. $day = '([0-9]{1,2})';
  8553. $hour = $sec = $min = '([0-9]{2})';
  8554. $year = '([0-9]{4})';
  8555. $terminator = '\x0A?\x00?';
  8556. $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
  8557. }
  8558. if (preg_match($pcre, $date, $match))
  8559. {
  8560. /*
  8561. Capturing subpatterns:
  8562. 1: Day name
  8563. 2: Month
  8564. 3: Day
  8565. 4: Hour
  8566. 5: Minute
  8567. 6: Second
  8568. 7: Year
  8569. */
  8570. $month = $this->month[strtolower($match[2])];
  8571. return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
  8572. }
  8573. else
  8574. {
  8575. return false;
  8576. }
  8577. }
  8578. /**
  8579. * Parse dates using strtotime()
  8580. *
  8581. * @access protected
  8582. * @return int Timestamp
  8583. */
  8584. public function date_strtotime($date)
  8585. {
  8586. $strtotime = strtotime($date);
  8587. if ($strtotime === -1 || $strtotime === false)
  8588. {
  8589. return false;
  8590. }
  8591. else
  8592. {
  8593. return $strtotime;
  8594. }
  8595. }
  8596. }
  8597. /**
  8598. * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
  8599. *
  8600. * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
  8601. *
  8602. * This class can be overloaded with {@see SimplePie::set_rating_class()}
  8603. *
  8604. * @package SimplePie
  8605. * @subpackage API
  8606. */
  8607. class SimplePie_Rating
  8608. {
  8609. /**
  8610. * Rating scheme
  8611. *
  8612. * @var string
  8613. * @see get_scheme()
  8614. */
  8615. var $scheme;
  8616. /**
  8617. * Rating value
  8618. *
  8619. * @var string
  8620. * @see get_value()
  8621. */
  8622. var $value;
  8623. /**
  8624. * Constructor, used to input the data
  8625. *
  8626. * For documentation on all the parameters, see the corresponding
  8627. * properties and their accessors
  8628. */
  8629. public function __construct($scheme = null, $value = null)
  8630. {
  8631. $this->scheme = $scheme;
  8632. $this->value = $value;
  8633. }
  8634. /**
  8635. * String-ified version
  8636. *
  8637. * @return string
  8638. */
  8639. public function __toString()
  8640. {
  8641. // There is no $this->data here
  8642. return md5(serialize($this));
  8643. }
  8644. /**
  8645. * Get the organizational scheme for the rating
  8646. *
  8647. * @return string|null
  8648. */
  8649. public function get_scheme()
  8650. {
  8651. if ($this->scheme !== null)
  8652. {
  8653. return $this->scheme;
  8654. }
  8655. else
  8656. {
  8657. return null;
  8658. }
  8659. }
  8660. /**
  8661. * Get the value of the rating
  8662. *
  8663. * @return string|null
  8664. */
  8665. public function get_value()
  8666. {
  8667. if ($this->value !== null)
  8668. {
  8669. return $this->value;
  8670. }
  8671. else
  8672. {
  8673. return null;
  8674. }
  8675. }
  8676. }
  8677. /**
  8678. * Manages all author-related data
  8679. *
  8680. * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
  8681. *
  8682. * This class can be overloaded with {@see SimplePie::set_author_class()}
  8683. *
  8684. * @package SimplePie
  8685. * @subpackage API
  8686. */
  8687. class SimplePie_Author
  8688. {
  8689. /**
  8690. * Author's name
  8691. *
  8692. * @var string
  8693. * @see get_name()
  8694. */
  8695. var $name;
  8696. /**
  8697. * Author's link
  8698. *
  8699. * @var string
  8700. * @see get_link()
  8701. */
  8702. var $link;
  8703. /**
  8704. * Author's email address
  8705. *
  8706. * @var string
  8707. * @see get_email()
  8708. */
  8709. var $email;
  8710. /**
  8711. * Constructor, used to input the data
  8712. *
  8713. * @param string $name
  8714. * @param string $link
  8715. * @param string $email
  8716. */
  8717. public function __construct($name = null, $link = null, $email = null)
  8718. {
  8719. $this->name = $name;
  8720. $this->link = $link;
  8721. $this->email = $email;
  8722. }
  8723. /**
  8724. * String-ified version
  8725. *
  8726. * @return string
  8727. */
  8728. public function __toString()
  8729. {
  8730. // There is no $this->data here
  8731. return md5(serialize($this));
  8732. }
  8733. /**
  8734. * Author's name
  8735. *
  8736. * @return string|null
  8737. */
  8738. public function get_name()
  8739. {
  8740. if ($this->name !== null)
  8741. {
  8742. return $this->name;
  8743. }
  8744. else
  8745. {
  8746. return null;
  8747. }
  8748. }
  8749. /**
  8750. * Author's link
  8751. *
  8752. * @return string|null
  8753. */
  8754. public function get_link()
  8755. {
  8756. if ($this->link !== null)
  8757. {
  8758. return $this->link;
  8759. }
  8760. else
  8761. {
  8762. return null;
  8763. }
  8764. }
  8765. /**
  8766. * Author's email address
  8767. *
  8768. * @return string|null
  8769. */
  8770. public function get_email()
  8771. {
  8772. if ($this->email !== null)
  8773. {
  8774. return $this->email;
  8775. }
  8776. else
  8777. {
  8778. return null;
  8779. }
  8780. }
  8781. }
  8782. /**
  8783. * Content-type sniffing
  8784. *
  8785. * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
  8786. *
  8787. * This is used since we can't always trust Content-Type headers, and is based
  8788. * upon the HTML5 parsing rules.
  8789. *
  8790. *
  8791. * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
  8792. *
  8793. * @package SimplePie
  8794. * @subpackage HTTP
  8795. */
  8796. class SimplePie_Content_Type_Sniffer
  8797. {
  8798. /**
  8799. * File object
  8800. *
  8801. * @var SimplePie_File
  8802. */
  8803. var $file;
  8804. /**
  8805. * Create an instance of the class with the input file
  8806. *
  8807. * @param SimplePie_Content_Type_Sniffer $file Input file
  8808. */
  8809. public function __construct($file)
  8810. {
  8811. $this->file = $file;
  8812. }
  8813. /**
  8814. * Get the Content-Type of the specified file
  8815. *
  8816. * @return string Actual Content-Type
  8817. */
  8818. public function get_type()
  8819. {
  8820. if (isset($this->file->headers['content-type']))
  8821. {
  8822. if (!isset($this->file->headers['content-encoding'])
  8823. && ($this->file->headers['content-type'] === 'text/plain'
  8824. || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
  8825. || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
  8826. || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
  8827. {
  8828. return $this->text_or_binary();
  8829. }
  8830. if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
  8831. {
  8832. $official = substr($this->file->headers['content-type'], 0, $pos);
  8833. }
  8834. else
  8835. {
  8836. $official = $this->file->headers['content-type'];
  8837. }
  8838. $official = trim(strtolower($official));
  8839. if ($official === 'unknown/unknown'
  8840. || $official === 'application/unknown')
  8841. {
  8842. return $this->unknown();
  8843. }
  8844. elseif (substr($official, -4) === '+xml'
  8845. || $official === 'text/xml'
  8846. || $official === 'application/xml')
  8847. {
  8848. return $official;
  8849. }
  8850. elseif (substr($official, 0, 6) === 'image/')
  8851. {
  8852. if ($return = $this->image())
  8853. {
  8854. return $return;
  8855. }
  8856. else
  8857. {
  8858. return $official;
  8859. }
  8860. }
  8861. elseif ($official === 'text/html')
  8862. {
  8863. return $this->feed_or_html();
  8864. }
  8865. else
  8866. {
  8867. return $official;
  8868. }
  8869. }
  8870. else
  8871. {
  8872. return $this->unknown();
  8873. }
  8874. }
  8875. /**
  8876. * Sniff text or binary
  8877. *
  8878. * @return string Actual Content-Type
  8879. */
  8880. public function text_or_binary()
  8881. {
  8882. if (substr($this->file->body, 0, 2) === "\xFE\xFF"
  8883. || substr($this->file->body, 0, 2) === "\xFF\xFE"
  8884. || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
  8885. || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
  8886. {
  8887. return 'text/plain';
  8888. }
  8889. elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
  8890. {
  8891. return 'application/octect-stream';
  8892. }
  8893. else
  8894. {
  8895. return 'text/plain';
  8896. }
  8897. }
  8898. /**
  8899. * Sniff unknown
  8900. *
  8901. * @return string Actual Content-Type
  8902. */
  8903. public function unknown()
  8904. {
  8905. $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
  8906. if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
  8907. || strtolower(substr($this->file->body, $ws, 5)) === '<html'
  8908. || strtolower(substr($this->file->body, $ws, 7)) === '<script')
  8909. {
  8910. return 'text/html';
  8911. }
  8912. elseif (substr($this->file->body, 0, 5) === '%PDF-')
  8913. {
  8914. return 'application/pdf';
  8915. }
  8916. elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
  8917. {
  8918. return 'application/postscript';
  8919. }
  8920. elseif (substr($this->file->body, 0, 6) === 'GIF87a'
  8921. || substr($this->file->body, 0, 6) === 'GIF89a')
  8922. {
  8923. return 'image/gif';
  8924. }
  8925. elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
  8926. {
  8927. return 'image/png';
  8928. }
  8929. elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
  8930. {
  8931. return 'image/jpeg';
  8932. }
  8933. elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
  8934. {
  8935. return 'image/bmp';
  8936. }
  8937. elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
  8938. {
  8939. return 'image/vnd.microsoft.icon';
  8940. }
  8941. else
  8942. {
  8943. return $this->text_or_binary();
  8944. }
  8945. }
  8946. /**
  8947. * Sniff images
  8948. *
  8949. * @return string Actual Content-Type
  8950. */
  8951. public function image()
  8952. {
  8953. if (substr($this->file->body, 0, 6) === 'GIF87a'
  8954. || substr($this->file->body, 0, 6) === 'GIF89a')
  8955. {
  8956. return 'image/gif';
  8957. }
  8958. elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
  8959. {
  8960. return 'image/png';
  8961. }
  8962. elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
  8963. {
  8964. return 'image/jpeg';
  8965. }
  8966. elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
  8967. {
  8968. return 'image/bmp';
  8969. }
  8970. elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
  8971. {
  8972. return 'image/vnd.microsoft.icon';
  8973. }
  8974. else
  8975. {
  8976. return false;
  8977. }
  8978. }
  8979. /**
  8980. * Sniff HTML
  8981. *
  8982. * @return string Actual Content-Type
  8983. */
  8984. public function feed_or_html()
  8985. {
  8986. $len = strlen($this->file->body);
  8987. $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
  8988. while ($pos < $len)
  8989. {
  8990. switch ($this->file->body[$pos])
  8991. {
  8992. case "\x09":
  8993. case "\x0A":
  8994. case "\x0D":
  8995. case "\x20":
  8996. $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
  8997. continue 2;
  8998. case '<':
  8999. $pos++;
  9000. break;
  9001. default:
  9002. return 'text/html';
  9003. }
  9004. if (substr($this->file->body, $pos, 3) === '!--')
  9005. {
  9006. $pos += 3;
  9007. if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
  9008. {
  9009. $pos += 3;
  9010. }
  9011. else
  9012. {
  9013. return 'text/html';
  9014. }
  9015. }
  9016. elseif (substr($this->file->body, $pos, 1) === '!')
  9017. {
  9018. if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
  9019. {
  9020. $pos++;
  9021. }
  9022. else
  9023. {
  9024. return 'text/html';
  9025. }
  9026. }
  9027. elseif (substr($this->file->body, $pos, 1) === '?')
  9028. {
  9029. if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
  9030. {
  9031. $pos += 2;
  9032. }
  9033. else
  9034. {
  9035. return 'text/html';
  9036. }
  9037. }
  9038. elseif (substr($this->file->body, $pos, 3) === 'rss'
  9039. || substr($this->file->body, $pos, 7) === 'rdf:RDF')
  9040. {
  9041. return 'application/rss+xml';
  9042. }
  9043. elseif (substr($this->file->body, $pos, 4) === 'feed')
  9044. {
  9045. return 'application/atom+xml';
  9046. }
  9047. else
  9048. {
  9049. return 'text/html';
  9050. }
  9051. }
  9052. return 'text/html';
  9053. }
  9054. }
  9055. /**
  9056. * Used for feed auto-discovery
  9057. *
  9058. *
  9059. * This class can be overloaded with {@see SimplePie::set_locator_class()}
  9060. *
  9061. * @package SimplePie
  9062. */
  9063. class SimplePie_Locator
  9064. {
  9065. var $useragent;
  9066. var $timeout;
  9067. var $file;
  9068. var $local = array();
  9069. var $elsewhere = array();
  9070. var $cached_entities = array();
  9071. var $http_base;
  9072. var $base;
  9073. var $base_location = 0;
  9074. var $checked_feeds = 0;
  9075. var $max_checked_feeds = 10;
  9076. protected $registry;
  9077. public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
  9078. {
  9079. $this->file = $file;
  9080. $this->useragent = $useragent;
  9081. $this->timeout = $timeout;
  9082. $this->max_checked_feeds = $max_checked_feeds;
  9083. $this->dom = new DOMDocument();
  9084. set_error_handler(array('SimplePie_Misc', 'silence_errors'));
  9085. $this->dom->loadHTML($this->file->body);
  9086. restore_error_handler();
  9087. }
  9088. public function set_registry(SimplePie_Registry $registry)
  9089. {
  9090. $this->registry = $registry;
  9091. }
  9092. public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
  9093. {
  9094. if ($this->is_feed($this->file))
  9095. {
  9096. return $this->file;
  9097. }
  9098. if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
  9099. {
  9100. $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
  9101. if ($sniffer->get_type() !== 'text/html')
  9102. {
  9103. return null;
  9104. }
  9105. }
  9106. if ($type & ~SIMPLEPIE_LOCATOR_NONE)
  9107. {
  9108. $this->get_base();
  9109. }
  9110. if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
  9111. {
  9112. return $working[0];
  9113. }
  9114. if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
  9115. {
  9116. if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
  9117. {
  9118. return $working;
  9119. }
  9120. if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
  9121. {
  9122. return $working;
  9123. }
  9124. if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
  9125. {
  9126. return $working;
  9127. }
  9128. if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
  9129. {
  9130. return $working;
  9131. }
  9132. }
  9133. return null;
  9134. }
  9135. public function is_feed($file)
  9136. {
  9137. if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
  9138. {
  9139. $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
  9140. $sniffed = $sniffer->get_type();
  9141. if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
  9142. {
  9143. return true;
  9144. }
  9145. else
  9146. {
  9147. return false;
  9148. }
  9149. }
  9150. elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
  9151. {
  9152. return true;
  9153. }
  9154. else
  9155. {
  9156. return false;
  9157. }
  9158. }
  9159. public function get_base()
  9160. {
  9161. $this->http_base = $this->file->url;
  9162. $this->base = $this->http_base;
  9163. $elements = $this->dom->getElementsByTagName('base');
  9164. foreach ($elements as $element)
  9165. {
  9166. if ($element->hasAttribute('href'))
  9167. {
  9168. $this->base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
  9169. $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
  9170. break;
  9171. }
  9172. }
  9173. }
  9174. public function autodiscovery()
  9175. {
  9176. $done = array();
  9177. $feeds = array();
  9178. $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
  9179. $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
  9180. $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
  9181. if (!empty($feeds))
  9182. {
  9183. return array_values($feeds);
  9184. }
  9185. else
  9186. {
  9187. return null;
  9188. }
  9189. }
  9190. protected function search_elements_by_tag($name, &$done, $feeds)
  9191. {
  9192. $links = $this->dom->getElementsByTagName($name);
  9193. foreach ($links as $link)
  9194. {
  9195. if ($this->checked_feeds === $this->max_checked_feeds)
  9196. {
  9197. break;
  9198. }
  9199. if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
  9200. {
  9201. $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
  9202. $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
  9203. if ($this->base_location < $line)
  9204. {
  9205. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
  9206. }
  9207. else
  9208. {
  9209. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
  9210. }
  9211. if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
  9212. {
  9213. $this->checked_feeds++;
  9214. $headers = array(
  9215. 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
  9216. );
  9217. $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
  9218. if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
  9219. {
  9220. $feeds[$href] = $feed;
  9221. }
  9222. }
  9223. $done[] = $href;
  9224. }
  9225. }
  9226. return $feeds;
  9227. }
  9228. public function get_links()
  9229. {
  9230. $links = $this->dom->getElementsByTagName('a');
  9231. foreach ($links as $link)
  9232. {
  9233. if ($link->hasAttribute('href'))
  9234. {
  9235. $href = trim($link->getAttribute('href'));
  9236. $parsed = $this->registry->call('Misc', 'parse_url', array($href));
  9237. if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
  9238. {
  9239. if ($this->base_location < $link->getLineNo())
  9240. {
  9241. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
  9242. }
  9243. else
  9244. {
  9245. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
  9246. }
  9247. $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
  9248. if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
  9249. {
  9250. $this->local[] = $href;
  9251. }
  9252. else
  9253. {
  9254. $this->elsewhere[] = $href;
  9255. }
  9256. }
  9257. }
  9258. }
  9259. $this->local = array_unique($this->local);
  9260. $this->elsewhere = array_unique($this->elsewhere);
  9261. if (!empty($this->local) || !empty($this->elsewhere))
  9262. {
  9263. return true;
  9264. }
  9265. return null;
  9266. }
  9267. public function extension(&$array)
  9268. {
  9269. foreach ($array as $key => $value)
  9270. {
  9271. if ($this->checked_feeds === $this->max_checked_feeds)
  9272. {
  9273. break;
  9274. }
  9275. if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
  9276. {
  9277. $this->checked_feeds++;
  9278. $headers = array(
  9279. 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
  9280. );
  9281. $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
  9282. if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
  9283. {
  9284. return $feed;
  9285. }
  9286. else
  9287. {
  9288. unset($array[$key]);
  9289. }
  9290. }
  9291. }
  9292. return null;
  9293. }
  9294. public function body(&$array)
  9295. {
  9296. foreach ($array as $key => $value)
  9297. {
  9298. if ($this->checked_feeds === $this->max_checked_feeds)
  9299. {
  9300. break;
  9301. }
  9302. if (preg_match('/(rss|rdf|atom|xml)/i', $value))
  9303. {
  9304. $this->checked_feeds++;
  9305. $headers = array(
  9306. 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
  9307. );
  9308. $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
  9309. if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
  9310. {
  9311. return $feed;
  9312. }
  9313. else
  9314. {
  9315. unset($array[$key]);
  9316. }
  9317. }
  9318. }
  9319. return null;
  9320. }
  9321. }
  9322. /**
  9323. * Manages all item-related data
  9324. *
  9325. * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
  9326. *
  9327. * This class can be overloaded with {@see SimplePie::set_item_class()}
  9328. *
  9329. * @package SimplePie
  9330. * @subpackage API
  9331. */
  9332. class SimplePie_Item
  9333. {
  9334. /**
  9335. * Parent feed
  9336. *
  9337. * @access private
  9338. * @var SimplePie
  9339. */
  9340. var $feed;
  9341. /**
  9342. * Raw data
  9343. *
  9344. * @access private
  9345. * @var array
  9346. */
  9347. var $data = array();
  9348. /**
  9349. * Registry object
  9350. *
  9351. * @see set_registry
  9352. * @var SimplePie_Registry
  9353. */
  9354. protected $registry;
  9355. /**
  9356. * Create a new item object
  9357. *
  9358. * This is usually used by {@see SimplePie::get_items} and
  9359. * {@see SimplePie::get_item}. Avoid creating this manually.
  9360. *
  9361. * @param SimplePie $feed Parent feed
  9362. * @param array $data Raw data
  9363. */
  9364. public function __construct($feed, $data)
  9365. {
  9366. $this->feed = $feed;
  9367. $this->data = $data;
  9368. }
  9369. /**
  9370. * Set the registry handler
  9371. *
  9372. * This is usually used by {@see SimplePie_Registry::create}
  9373. *
  9374. * @since 1.3
  9375. * @param SimplePie_Registry $registry
  9376. */
  9377. public function set_registry(SimplePie_Registry $registry)
  9378. {
  9379. $this->registry = $registry;
  9380. }
  9381. /**
  9382. * Get a string representation of the item
  9383. *
  9384. * @return string
  9385. */
  9386. public function __toString()
  9387. {
  9388. return md5(serialize($this->data));
  9389. }
  9390. /**
  9391. * Remove items that link back to this before destroying this object
  9392. */
  9393. public function __destruct()
  9394. {
  9395. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  9396. {
  9397. unset($this->feed);
  9398. }
  9399. }
  9400. /**
  9401. * Get data for an item-level element
  9402. *
  9403. * This method allows you to get access to ANY element/attribute that is a
  9404. * sub-element of the item/entry tag.
  9405. *
  9406. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  9407. *
  9408. * @since 1.0
  9409. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  9410. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  9411. * @param string $tag Tag name
  9412. * @return array
  9413. */
  9414. public function get_item_tags($namespace, $tag)
  9415. {
  9416. if (isset($this->data['child'][$namespace][$tag]))
  9417. {
  9418. return $this->data['child'][$namespace][$tag];
  9419. }
  9420. else
  9421. {
  9422. return null;
  9423. }
  9424. }
  9425. /**
  9426. * Get the base URL value from the parent feed
  9427. *
  9428. * Uses `<xml:base>`
  9429. *
  9430. * @param array $element
  9431. * @return string
  9432. */
  9433. public function get_base($element = array())
  9434. {
  9435. return $this->feed->get_base($element);
  9436. }
  9437. /**
  9438. * Sanitize feed data
  9439. *
  9440. * @access private
  9441. * @see SimplePie::sanitize()
  9442. * @param string $data Data to sanitize
  9443. * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
  9444. * @param string $base Base URL to resolve URLs against
  9445. * @return string Sanitized data
  9446. */
  9447. public function sanitize($data, $type, $base = '')
  9448. {
  9449. return $this->feed->sanitize($data, $type, $base);
  9450. }
  9451. /**
  9452. * Get the parent feed
  9453. *
  9454. * Note: this may not work as you think for multifeeds!
  9455. *
  9456. * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
  9457. * @since 1.0
  9458. * @return SimplePie
  9459. */
  9460. public function get_feed()
  9461. {
  9462. return $this->feed;
  9463. }
  9464. /**
  9465. * Get the unique identifier for the item
  9466. *
  9467. * This is usually used when writing code to check for new items in a feed.
  9468. *
  9469. * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
  9470. * for RDF. If none of these are supplied (or `$hash` is true), creates an
  9471. * MD5 hash based on the permalink and title. If either of those are not
  9472. * supplied, creates a hash based on the full feed data.
  9473. *
  9474. * @since Beta 2
  9475. * @param boolean $hash Should we force using a hash instead of the supplied ID?
  9476. * @return string
  9477. */
  9478. public function get_id($hash = false)
  9479. {
  9480. if (!$hash)
  9481. {
  9482. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
  9483. {
  9484. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9485. }
  9486. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
  9487. {
  9488. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9489. }
  9490. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  9491. {
  9492. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9493. }
  9494. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
  9495. {
  9496. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9497. }
  9498. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
  9499. {
  9500. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9501. }
  9502. elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
  9503. {
  9504. return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
  9505. }
  9506. elseif (($return = $this->get_permalink()) !== null)
  9507. {
  9508. return $return;
  9509. }
  9510. elseif (($return = $this->get_title()) !== null)
  9511. {
  9512. return $return;
  9513. }
  9514. }
  9515. if ($this->get_permalink() !== null || $this->get_title() !== null)
  9516. {
  9517. return md5($this->get_permalink() . $this->get_title());
  9518. }
  9519. else
  9520. {
  9521. return md5(serialize($this->data));
  9522. }
  9523. }
  9524. /**
  9525. * Get the title of the item
  9526. *
  9527. * Uses `<atom:title>`, `<title>` or `<dc:title>`
  9528. *
  9529. * @since Beta 2 (previously called `get_item_title` since 0.8)
  9530. * @return string|null
  9531. */
  9532. public function get_title()
  9533. {
  9534. if (!isset($this->data['title']))
  9535. {
  9536. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  9537. {
  9538. $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9539. }
  9540. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  9541. {
  9542. $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9543. }
  9544. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  9545. {
  9546. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9547. }
  9548. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  9549. {
  9550. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9551. }
  9552. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  9553. {
  9554. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9555. }
  9556. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  9557. {
  9558. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9559. }
  9560. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  9561. {
  9562. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9563. }
  9564. else
  9565. {
  9566. $this->data['title'] = null;
  9567. }
  9568. }
  9569. return $this->data['title'];
  9570. }
  9571. /**
  9572. * Get the content for the item
  9573. *
  9574. * Prefers summaries over full content , but will return full content if a
  9575. * summary does not exist.
  9576. *
  9577. * To prefer full content instead, use {@see get_content}
  9578. *
  9579. * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
  9580. * `<itunes:subtitle>`
  9581. *
  9582. * @since 0.8
  9583. * @param boolean $description_only Should we avoid falling back to the content?
  9584. * @return string|null
  9585. */
  9586. public function get_description($description_only = false)
  9587. {
  9588. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
  9589. {
  9590. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9591. }
  9592. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
  9593. {
  9594. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9595. }
  9596. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  9597. {
  9598. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9599. }
  9600. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  9601. {
  9602. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  9603. }
  9604. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  9605. {
  9606. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9607. }
  9608. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  9609. {
  9610. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9611. }
  9612. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  9613. {
  9614. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  9615. }
  9616. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  9617. {
  9618. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9619. }
  9620. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  9621. {
  9622. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
  9623. }
  9624. elseif (!$description_only)
  9625. {
  9626. return $this->get_content(true);
  9627. }
  9628. else
  9629. {
  9630. return null;
  9631. }
  9632. }
  9633. /**
  9634. * Get the content for the item
  9635. *
  9636. * Prefers full content over summaries, but will return a summary if full
  9637. * content does not exist.
  9638. *
  9639. * To prefer summaries instead, use {@see get_description}
  9640. *
  9641. * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
  9642. *
  9643. * @since 1.0
  9644. * @param boolean $content_only Should we avoid falling back to the description?
  9645. * @return string|null
  9646. */
  9647. public function get_content($content_only = false)
  9648. {
  9649. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
  9650. {
  9651. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9652. }
  9653. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
  9654. {
  9655. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9656. }
  9657. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
  9658. {
  9659. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  9660. }
  9661. elseif (!$content_only)
  9662. {
  9663. return $this->get_description(true);
  9664. }
  9665. else
  9666. {
  9667. return null;
  9668. }
  9669. }
  9670. /**
  9671. * Get a category for the item
  9672. *
  9673. * @since Beta 3 (previously called `get_categories()` since Beta 2)
  9674. * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
  9675. * @return SimplePie_Category|null
  9676. */
  9677. public function get_category($key = 0)
  9678. {
  9679. $categories = $this->get_categories();
  9680. if (isset($categories[$key]))
  9681. {
  9682. return $categories[$key];
  9683. }
  9684. else
  9685. {
  9686. return null;
  9687. }
  9688. }
  9689. /**
  9690. * Get all categories for the item
  9691. *
  9692. * Uses `<atom:category>`, `<category>` or `<dc:subject>`
  9693. *
  9694. * @since Beta 3
  9695. * @return array|null List of {@see SimplePie_Category} objects
  9696. */
  9697. public function get_categories()
  9698. {
  9699. $categories = array();
  9700. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  9701. {
  9702. $term = null;
  9703. $scheme = null;
  9704. $label = null;
  9705. if (isset($category['attribs']['']['term']))
  9706. {
  9707. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  9708. }
  9709. if (isset($category['attribs']['']['scheme']))
  9710. {
  9711. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9712. }
  9713. if (isset($category['attribs']['']['label']))
  9714. {
  9715. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  9716. }
  9717. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  9718. }
  9719. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  9720. {
  9721. // This is really the label, but keep this as the term also for BC.
  9722. // Label will also work on retrieving because that falls back to term.
  9723. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9724. if (isset($category['attribs']['']['domain']))
  9725. {
  9726. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  9727. }
  9728. else
  9729. {
  9730. $scheme = null;
  9731. }
  9732. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  9733. }
  9734. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  9735. {
  9736. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  9737. }
  9738. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  9739. {
  9740. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  9741. }
  9742. if (!empty($categories))
  9743. {
  9744. return array_unique($categories);
  9745. }
  9746. else
  9747. {
  9748. return null;
  9749. }
  9750. }
  9751. /**
  9752. * Get an author for the item
  9753. *
  9754. * @since Beta 2
  9755. * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
  9756. * @return SimplePie_Author|null
  9757. */
  9758. public function get_author($key = 0)
  9759. {
  9760. $authors = $this->get_authors();
  9761. if (isset($authors[$key]))
  9762. {
  9763. return $authors[$key];
  9764. }
  9765. else
  9766. {
  9767. return null;
  9768. }
  9769. }
  9770. /**
  9771. * Get a contributor for the item
  9772. *
  9773. * @since 1.1
  9774. * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
  9775. * @return SimplePie_Author|null
  9776. */
  9777. public function get_contributor($key = 0)
  9778. {
  9779. $contributors = $this->get_contributors();
  9780. if (isset($contributors[$key]))
  9781. {
  9782. return $contributors[$key];
  9783. }
  9784. else
  9785. {
  9786. return null;
  9787. }
  9788. }
  9789. /**
  9790. * Get all contributors for the item
  9791. *
  9792. * Uses `<atom:contributor>`
  9793. *
  9794. * @since 1.1
  9795. * @return array|null List of {@see SimplePie_Author} objects
  9796. */
  9797. public function get_contributors()
  9798. {
  9799. $contributors = array();
  9800. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  9801. {
  9802. $name = null;
  9803. $uri = null;
  9804. $email = null;
  9805. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  9806. {
  9807. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9808. }
  9809. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  9810. {
  9811. $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]));
  9812. }
  9813. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  9814. {
  9815. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9816. }
  9817. if ($name !== null || $email !== null || $uri !== null)
  9818. {
  9819. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  9820. }
  9821. }
  9822. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  9823. {
  9824. $name = null;
  9825. $url = null;
  9826. $email = null;
  9827. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  9828. {
  9829. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9830. }
  9831. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  9832. {
  9833. $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]));
  9834. }
  9835. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  9836. {
  9837. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9838. }
  9839. if ($name !== null || $email !== null || $url !== null)
  9840. {
  9841. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  9842. }
  9843. }
  9844. if (!empty($contributors))
  9845. {
  9846. return array_unique($contributors);
  9847. }
  9848. else
  9849. {
  9850. return null;
  9851. }
  9852. }
  9853. /**
  9854. * Get all authors for the item
  9855. *
  9856. * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
  9857. *
  9858. * @since Beta 2
  9859. * @return array|null List of {@see SimplePie_Author} objects
  9860. */
  9861. public function get_authors()
  9862. {
  9863. $authors = array();
  9864. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  9865. {
  9866. $name = null;
  9867. $uri = null;
  9868. $email = null;
  9869. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  9870. {
  9871. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9872. }
  9873. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  9874. {
  9875. $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]));
  9876. }
  9877. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  9878. {
  9879. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9880. }
  9881. if ($name !== null || $email !== null || $uri !== null)
  9882. {
  9883. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  9884. }
  9885. }
  9886. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  9887. {
  9888. $name = null;
  9889. $url = null;
  9890. $email = null;
  9891. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  9892. {
  9893. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9894. }
  9895. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  9896. {
  9897. $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]));
  9898. }
  9899. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  9900. {
  9901. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9902. }
  9903. if ($name !== null || $email !== null || $url !== null)
  9904. {
  9905. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  9906. }
  9907. }
  9908. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
  9909. {
  9910. $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
  9911. }
  9912. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  9913. {
  9914. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  9915. }
  9916. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  9917. {
  9918. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  9919. }
  9920. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  9921. {
  9922. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  9923. }
  9924. if (!empty($authors))
  9925. {
  9926. return array_unique($authors);
  9927. }
  9928. elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
  9929. {
  9930. return $authors;
  9931. }
  9932. elseif ($authors = $this->feed->get_authors())
  9933. {
  9934. return $authors;
  9935. }
  9936. else
  9937. {
  9938. return null;
  9939. }
  9940. }
  9941. /**
  9942. * Get the copyright info for the item
  9943. *
  9944. * Uses `<atom:rights>` or `<dc:rights>`
  9945. *
  9946. * @since 1.1
  9947. * @return string
  9948. */
  9949. public function get_copyright()
  9950. {
  9951. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  9952. {
  9953. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9954. }
  9955. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  9956. {
  9957. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9958. }
  9959. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  9960. {
  9961. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9962. }
  9963. else
  9964. {
  9965. return null;
  9966. }
  9967. }
  9968. /**
  9969. * Get the posting date/time for the item
  9970. *
  9971. * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
  9972. * `<atom:modified>`, `<pubDate>` or `<dc:date>`
  9973. *
  9974. * Note: obeys PHP's timezone setting. To get a UTC date/time, use
  9975. * {@see get_gmdate}
  9976. *
  9977. * @since Beta 2 (previously called `get_item_date` since 0.8)
  9978. *
  9979. * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
  9980. * @return int|string|null
  9981. */
  9982. public function get_date($date_format = 'j F Y, g:i a')
  9983. {
  9984. if (!isset($this->data['date']))
  9985. {
  9986. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
  9987. {
  9988. $this->data['date']['raw'] = $return[0]['data'];
  9989. }
  9990. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
  9991. {
  9992. $this->data['date']['raw'] = $return[0]['data'];
  9993. }
  9994. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
  9995. {
  9996. $this->data['date']['raw'] = $return[0]['data'];
  9997. }
  9998. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
  9999. {
  10000. $this->data['date']['raw'] = $return[0]['data'];
  10001. }
  10002. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
  10003. {
  10004. $this->data['date']['raw'] = $return[0]['data'];
  10005. }
  10006. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
  10007. {
  10008. $this->data['date']['raw'] = $return[0]['data'];
  10009. }
  10010. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
  10011. {
  10012. $this->data['date']['raw'] = $return[0]['data'];
  10013. }
  10014. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
  10015. {
  10016. $this->data['date']['raw'] = $return[0]['data'];
  10017. }
  10018. if (!empty($this->data['date']['raw']))
  10019. {
  10020. $parser = $this->registry->call('Parse_Date', 'get');
  10021. $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
  10022. }
  10023. else
  10024. {
  10025. $this->data['date'] = null;
  10026. }
  10027. }
  10028. if ($this->data['date'])
  10029. {
  10030. $date_format = (string) $date_format;
  10031. switch ($date_format)
  10032. {
  10033. case '':
  10034. return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
  10035. case 'U':
  10036. return $this->data['date']['parsed'];
  10037. default:
  10038. return date($date_format, $this->data['date']['parsed']);
  10039. }
  10040. }
  10041. else
  10042. {
  10043. return null;
  10044. }
  10045. }
  10046. /**
  10047. * Get the update date/time for the item
  10048. *
  10049. * Uses `<atom:updated>`
  10050. *
  10051. * Note: obeys PHP's timezone setting. To get a UTC date/time, use
  10052. * {@see get_gmdate}
  10053. *
  10054. * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
  10055. * @return int|string|null
  10056. */
  10057. public function get_updated_date($date_format = 'j F Y, g:i a')
  10058. {
  10059. if (!isset($this->data['updated']))
  10060. {
  10061. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
  10062. {
  10063. $this->data['updated']['raw'] = $return[0]['data'];
  10064. }
  10065. if (!empty($this->data['updated']['raw']))
  10066. {
  10067. $parser = $this->registry->call('Parse_Date', 'get');
  10068. $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
  10069. }
  10070. else
  10071. {
  10072. $this->data['updated'] = null;
  10073. }
  10074. }
  10075. if ($this->data['updated'])
  10076. {
  10077. $date_format = (string) $date_format;
  10078. switch ($date_format)
  10079. {
  10080. case '':
  10081. return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
  10082. case 'U':
  10083. return $this->data['updated']['parsed'];
  10084. default:
  10085. return date($date_format, $this->data['updated']['parsed']);
  10086. }
  10087. }
  10088. else
  10089. {
  10090. return null;
  10091. }
  10092. }
  10093. /**
  10094. * Get the localized posting date/time for the item
  10095. *
  10096. * Returns the date formatted in the localized language. To display in
  10097. * languages other than the server's default, you need to change the locale
  10098. * with {@link http://php.net/setlocale setlocale()}. The available
  10099. * localizations depend on which ones are installed on your web server.
  10100. *
  10101. * @since 1.0
  10102. *
  10103. * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
  10104. * @return int|string|null
  10105. */
  10106. public function get_local_date($date_format = '%c')
  10107. {
  10108. if (!$date_format)
  10109. {
  10110. return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
  10111. }
  10112. elseif (($date = $this->get_date('U')) !== null && $date !== false)
  10113. {
  10114. return strftime($date_format, $date);
  10115. }
  10116. else
  10117. {
  10118. return null;
  10119. }
  10120. }
  10121. /**
  10122. * Get the posting date/time for the item (UTC time)
  10123. *
  10124. * @see get_date
  10125. * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
  10126. * @return int|string|null
  10127. */
  10128. public function get_gmdate($date_format = 'j F Y, g:i a')
  10129. {
  10130. $date = $this->get_date('U');
  10131. if ($date === null)
  10132. {
  10133. return null;
  10134. }
  10135. return gmdate($date_format, $date);
  10136. }
  10137. /**
  10138. * Get the update date/time for the item (UTC time)
  10139. *
  10140. * @see get_updated_date
  10141. * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
  10142. * @return int|string|null
  10143. */
  10144. public function get_updated_gmdate($date_format = 'j F Y, g:i a')
  10145. {
  10146. $date = $this->get_updated_date('U');
  10147. if ($date === null)
  10148. {
  10149. return null;
  10150. }
  10151. return gmdate($date_format, $date);
  10152. }
  10153. /**
  10154. * Get the permalink for the item
  10155. *
  10156. * Returns the first link available with a relationship of "alternate".
  10157. * Identical to {@see get_link()} with key 0
  10158. *
  10159. * @see get_link
  10160. * @since 0.8
  10161. * @return string|null Permalink URL
  10162. */
  10163. public function get_permalink()
  10164. {
  10165. $link = $this->get_link();
  10166. $enclosure = $this->get_enclosure(0);
  10167. if ($link !== null)
  10168. {
  10169. return $link;
  10170. }
  10171. elseif ($enclosure !== null)
  10172. {
  10173. return $enclosure->get_link();
  10174. }
  10175. else
  10176. {
  10177. return null;
  10178. }
  10179. }
  10180. /**
  10181. * Get a single link for the item
  10182. *
  10183. * @since Beta 3
  10184. * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
  10185. * @param string $rel The relationship of the link to return
  10186. * @return string|null Link URL
  10187. */
  10188. public function get_link($key = 0, $rel = 'alternate')
  10189. {
  10190. $links = $this->get_links($rel);
  10191. if ($links[$key] !== null)
  10192. {
  10193. return $links[$key];
  10194. }
  10195. else
  10196. {
  10197. return null;
  10198. }
  10199. }
  10200. /**
  10201. * Get all links for the item
  10202. *
  10203. * Uses `<atom:link>`, `<link>` or `<guid>`
  10204. *
  10205. * @since Beta 2
  10206. * @param string $rel The relationship of links to return
  10207. * @return array|null Links found for the item (strings)
  10208. */
  10209. public function get_links($rel = 'alternate')
  10210. {
  10211. if (!isset($this->data['links']))
  10212. {
  10213. $this->data['links'] = array();
  10214. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  10215. {
  10216. if (isset($link['attribs']['']['href']))
  10217. {
  10218. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  10219. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  10220. }
  10221. }
  10222. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  10223. {
  10224. if (isset($link['attribs']['']['href']))
  10225. {
  10226. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  10227. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  10228. }
  10229. }
  10230. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  10231. {
  10232. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10233. }
  10234. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  10235. {
  10236. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10237. }
  10238. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  10239. {
  10240. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10241. }
  10242. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  10243. {
  10244. if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
  10245. {
  10246. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10247. }
  10248. }
  10249. $keys = array_keys($this->data['links']);
  10250. foreach ($keys as $key)
  10251. {
  10252. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  10253. {
  10254. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  10255. {
  10256. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  10257. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  10258. }
  10259. else
  10260. {
  10261. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  10262. }
  10263. }
  10264. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  10265. {
  10266. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  10267. }
  10268. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  10269. }
  10270. }
  10271. if (isset($this->data['links'][$rel]))
  10272. {
  10273. return $this->data['links'][$rel];
  10274. }
  10275. else
  10276. {
  10277. return null;
  10278. }
  10279. }
  10280. /**
  10281. * Get an enclosure from the item
  10282. *
  10283. * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
  10284. *
  10285. * @since Beta 2
  10286. * @todo Add ability to prefer one type of content over another (in a media group).
  10287. * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
  10288. * @return SimplePie_Enclosure|null
  10289. */
  10290. public function get_enclosure($key = 0, $prefer = null)
  10291. {
  10292. $enclosures = $this->get_enclosures();
  10293. if (isset($enclosures[$key]))
  10294. {
  10295. return $enclosures[$key];
  10296. }
  10297. else
  10298. {
  10299. return null;
  10300. }
  10301. }
  10302. /**
  10303. * Get all available enclosures (podcasts, etc.)
  10304. *
  10305. * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
  10306. *
  10307. * At this point, we're pretty much assuming that all enclosures for an item
  10308. * are the same content. Anything else is too complicated to
  10309. * properly support.
  10310. *
  10311. * @since Beta 2
  10312. * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
  10313. * @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).
  10314. * @return array|null List of SimplePie_Enclosure items
  10315. */
  10316. public function get_enclosures()
  10317. {
  10318. if (!isset($this->data['enclosures']))
  10319. {
  10320. $this->data['enclosures'] = array();
  10321. // Elements
  10322. $captions_parent = null;
  10323. $categories_parent = null;
  10324. $copyrights_parent = null;
  10325. $credits_parent = null;
  10326. $description_parent = null;
  10327. $duration_parent = null;
  10328. $hashes_parent = null;
  10329. $keywords_parent = null;
  10330. $player_parent = null;
  10331. $ratings_parent = null;
  10332. $restrictions_parent = null;
  10333. $thumbnails_parent = null;
  10334. $title_parent = null;
  10335. // Let's do the channel and item-level ones first, and just re-use them if we need to.
  10336. $parent = $this->get_feed();
  10337. // CAPTIONS
  10338. if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
  10339. {
  10340. foreach ($captions as $caption)
  10341. {
  10342. $caption_type = null;
  10343. $caption_lang = null;
  10344. $caption_startTime = null;
  10345. $caption_endTime = null;
  10346. $caption_text = null;
  10347. if (isset($caption['attribs']['']['type']))
  10348. {
  10349. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10350. }
  10351. if (isset($caption['attribs']['']['lang']))
  10352. {
  10353. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  10354. }
  10355. if (isset($caption['attribs']['']['start']))
  10356. {
  10357. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  10358. }
  10359. if (isset($caption['attribs']['']['end']))
  10360. {
  10361. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  10362. }
  10363. if (isset($caption['data']))
  10364. {
  10365. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10366. }
  10367. $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  10368. }
  10369. }
  10370. elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
  10371. {
  10372. foreach ($captions as $caption)
  10373. {
  10374. $caption_type = null;
  10375. $caption_lang = null;
  10376. $caption_startTime = null;
  10377. $caption_endTime = null;
  10378. $caption_text = null;
  10379. if (isset($caption['attribs']['']['type']))
  10380. {
  10381. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10382. }
  10383. if (isset($caption['attribs']['']['lang']))
  10384. {
  10385. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  10386. }
  10387. if (isset($caption['attribs']['']['start']))
  10388. {
  10389. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  10390. }
  10391. if (isset($caption['attribs']['']['end']))
  10392. {
  10393. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  10394. }
  10395. if (isset($caption['data']))
  10396. {
  10397. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10398. }
  10399. $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  10400. }
  10401. }
  10402. if (is_array($captions_parent))
  10403. {
  10404. $captions_parent = array_values(array_unique($captions_parent));
  10405. }
  10406. // CATEGORIES
  10407. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
  10408. {
  10409. $term = null;
  10410. $scheme = null;
  10411. $label = null;
  10412. if (isset($category['data']))
  10413. {
  10414. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10415. }
  10416. if (isset($category['attribs']['']['scheme']))
  10417. {
  10418. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10419. }
  10420. else
  10421. {
  10422. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  10423. }
  10424. if (isset($category['attribs']['']['label']))
  10425. {
  10426. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  10427. }
  10428. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10429. }
  10430. foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
  10431. {
  10432. $term = null;
  10433. $scheme = null;
  10434. $label = null;
  10435. if (isset($category['data']))
  10436. {
  10437. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10438. }
  10439. if (isset($category['attribs']['']['scheme']))
  10440. {
  10441. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10442. }
  10443. else
  10444. {
  10445. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  10446. }
  10447. if (isset($category['attribs']['']['label']))
  10448. {
  10449. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  10450. }
  10451. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10452. }
  10453. foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
  10454. {
  10455. $term = null;
  10456. $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
  10457. $label = null;
  10458. if (isset($category['attribs']['']['text']))
  10459. {
  10460. $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
  10461. }
  10462. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10463. if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
  10464. {
  10465. foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
  10466. {
  10467. if (isset($subcategory['attribs']['']['text']))
  10468. {
  10469. $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
  10470. }
  10471. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10472. }
  10473. }
  10474. }
  10475. if (is_array($categories_parent))
  10476. {
  10477. $categories_parent = array_values(array_unique($categories_parent));
  10478. }
  10479. // COPYRIGHT
  10480. if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
  10481. {
  10482. $copyright_url = null;
  10483. $copyright_label = null;
  10484. if (isset($copyright[0]['attribs']['']['url']))
  10485. {
  10486. $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  10487. }
  10488. if (isset($copyright[0]['data']))
  10489. {
  10490. $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10491. }
  10492. $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  10493. }
  10494. elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
  10495. {
  10496. $copyright_url = null;
  10497. $copyright_label = null;
  10498. if (isset($copyright[0]['attribs']['']['url']))
  10499. {
  10500. $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  10501. }
  10502. if (isset($copyright[0]['data']))
  10503. {
  10504. $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10505. }
  10506. $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  10507. }
  10508. // CREDITS
  10509. if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
  10510. {
  10511. foreach ($credits as $credit)
  10512. {
  10513. $credit_role = null;
  10514. $credit_scheme = null;
  10515. $credit_name = null;
  10516. if (isset($credit['attribs']['']['role']))
  10517. {
  10518. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  10519. }
  10520. if (isset($credit['attribs']['']['scheme']))
  10521. {
  10522. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10523. }
  10524. else
  10525. {
  10526. $credit_scheme = 'urn:ebu';
  10527. }
  10528. if (isset($credit['data']))
  10529. {
  10530. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10531. }
  10532. $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  10533. }
  10534. }
  10535. elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
  10536. {
  10537. foreach ($credits as $credit)
  10538. {
  10539. $credit_role = null;
  10540. $credit_scheme = null;
  10541. $credit_name = null;
  10542. if (isset($credit['attribs']['']['role']))
  10543. {
  10544. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  10545. }
  10546. if (isset($credit['attribs']['']['scheme']))
  10547. {
  10548. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10549. }
  10550. else
  10551. {
  10552. $credit_scheme = 'urn:ebu';
  10553. }
  10554. if (isset($credit['data']))
  10555. {
  10556. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10557. }
  10558. $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  10559. }
  10560. }
  10561. if (is_array($credits_parent))
  10562. {
  10563. $credits_parent = array_values(array_unique($credits_parent));
  10564. }
  10565. // DESCRIPTION
  10566. if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
  10567. {
  10568. if (isset($description_parent[0]['data']))
  10569. {
  10570. $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10571. }
  10572. }
  10573. elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
  10574. {
  10575. if (isset($description_parent[0]['data']))
  10576. {
  10577. $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10578. }
  10579. }
  10580. // DURATION
  10581. if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
  10582. {
  10583. $seconds = null;
  10584. $minutes = null;
  10585. $hours = null;
  10586. if (isset($duration_parent[0]['data']))
  10587. {
  10588. $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10589. if (sizeof($temp) > 0)
  10590. {
  10591. $seconds = (int) array_pop($temp);
  10592. }
  10593. if (sizeof($temp) > 0)
  10594. {
  10595. $minutes = (int) array_pop($temp);
  10596. $seconds += $minutes * 60;
  10597. }
  10598. if (sizeof($temp) > 0)
  10599. {
  10600. $hours = (int) array_pop($temp);
  10601. $seconds += $hours * 3600;
  10602. }
  10603. unset($temp);
  10604. $duration_parent = $seconds;
  10605. }
  10606. }
  10607. // HASHES
  10608. if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
  10609. {
  10610. foreach ($hashes_iterator as $hash)
  10611. {
  10612. $value = null;
  10613. $algo = null;
  10614. if (isset($hash['data']))
  10615. {
  10616. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10617. }
  10618. if (isset($hash['attribs']['']['algo']))
  10619. {
  10620. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  10621. }
  10622. else
  10623. {
  10624. $algo = 'md5';
  10625. }
  10626. $hashes_parent[] = $algo.':'.$value;
  10627. }
  10628. }
  10629. elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
  10630. {
  10631. foreach ($hashes_iterator as $hash)
  10632. {
  10633. $value = null;
  10634. $algo = null;
  10635. if (isset($hash['data']))
  10636. {
  10637. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10638. }
  10639. if (isset($hash['attribs']['']['algo']))
  10640. {
  10641. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  10642. }
  10643. else
  10644. {
  10645. $algo = 'md5';
  10646. }
  10647. $hashes_parent[] = $algo.':'.$value;
  10648. }
  10649. }
  10650. if (is_array($hashes_parent))
  10651. {
  10652. $hashes_parent = array_values(array_unique($hashes_parent));
  10653. }
  10654. // KEYWORDS
  10655. if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
  10656. {
  10657. if (isset($keywords[0]['data']))
  10658. {
  10659. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10660. foreach ($temp as $word)
  10661. {
  10662. $keywords_parent[] = trim($word);
  10663. }
  10664. }
  10665. unset($temp);
  10666. }
  10667. elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
  10668. {
  10669. if (isset($keywords[0]['data']))
  10670. {
  10671. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10672. foreach ($temp as $word)
  10673. {
  10674. $keywords_parent[] = trim($word);
  10675. }
  10676. }
  10677. unset($temp);
  10678. }
  10679. elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
  10680. {
  10681. if (isset($keywords[0]['data']))
  10682. {
  10683. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10684. foreach ($temp as $word)
  10685. {
  10686. $keywords_parent[] = trim($word);
  10687. }
  10688. }
  10689. unset($temp);
  10690. }
  10691. elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
  10692. {
  10693. if (isset($keywords[0]['data']))
  10694. {
  10695. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10696. foreach ($temp as $word)
  10697. {
  10698. $keywords_parent[] = trim($word);
  10699. }
  10700. }
  10701. unset($temp);
  10702. }
  10703. if (is_array($keywords_parent))
  10704. {
  10705. $keywords_parent = array_values(array_unique($keywords_parent));
  10706. }
  10707. // PLAYER
  10708. if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
  10709. {
  10710. if (isset($player_parent[0]['attribs']['']['url']))
  10711. {
  10712. $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10713. }
  10714. }
  10715. elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
  10716. {
  10717. if (isset($player_parent[0]['attribs']['']['url']))
  10718. {
  10719. $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10720. }
  10721. }
  10722. // RATINGS
  10723. if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
  10724. {
  10725. foreach ($ratings as $rating)
  10726. {
  10727. $rating_scheme = null;
  10728. $rating_value = null;
  10729. if (isset($rating['attribs']['']['scheme']))
  10730. {
  10731. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10732. }
  10733. else
  10734. {
  10735. $rating_scheme = 'urn:simple';
  10736. }
  10737. if (isset($rating['data']))
  10738. {
  10739. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10740. }
  10741. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10742. }
  10743. }
  10744. elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
  10745. {
  10746. foreach ($ratings as $rating)
  10747. {
  10748. $rating_scheme = 'urn:itunes';
  10749. $rating_value = null;
  10750. if (isset($rating['data']))
  10751. {
  10752. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10753. }
  10754. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10755. }
  10756. }
  10757. elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
  10758. {
  10759. foreach ($ratings as $rating)
  10760. {
  10761. $rating_scheme = null;
  10762. $rating_value = null;
  10763. if (isset($rating['attribs']['']['scheme']))
  10764. {
  10765. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10766. }
  10767. else
  10768. {
  10769. $rating_scheme = 'urn:simple';
  10770. }
  10771. if (isset($rating['data']))
  10772. {
  10773. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10774. }
  10775. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10776. }
  10777. }
  10778. elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
  10779. {
  10780. foreach ($ratings as $rating)
  10781. {
  10782. $rating_scheme = 'urn:itunes';
  10783. $rating_value = null;
  10784. if (isset($rating['data']))
  10785. {
  10786. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10787. }
  10788. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10789. }
  10790. }
  10791. if (is_array($ratings_parent))
  10792. {
  10793. $ratings_parent = array_values(array_unique($ratings_parent));
  10794. }
  10795. // RESTRICTIONS
  10796. if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
  10797. {
  10798. foreach ($restrictions as $restriction)
  10799. {
  10800. $restriction_relationship = null;
  10801. $restriction_type = null;
  10802. $restriction_value = null;
  10803. if (isset($restriction['attribs']['']['relationship']))
  10804. {
  10805. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  10806. }
  10807. if (isset($restriction['attribs']['']['type']))
  10808. {
  10809. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10810. }
  10811. if (isset($restriction['data']))
  10812. {
  10813. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10814. }
  10815. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10816. }
  10817. }
  10818. elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
  10819. {
  10820. foreach ($restrictions as $restriction)
  10821. {
  10822. $restriction_relationship = 'allow';
  10823. $restriction_type = null;
  10824. $restriction_value = 'itunes';
  10825. if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
  10826. {
  10827. $restriction_relationship = 'deny';
  10828. }
  10829. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10830. }
  10831. }
  10832. elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
  10833. {
  10834. foreach ($restrictions as $restriction)
  10835. {
  10836. $restriction_relationship = null;
  10837. $restriction_type = null;
  10838. $restriction_value = null;
  10839. if (isset($restriction['attribs']['']['relationship']))
  10840. {
  10841. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  10842. }
  10843. if (isset($restriction['attribs']['']['type']))
  10844. {
  10845. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10846. }
  10847. if (isset($restriction['data']))
  10848. {
  10849. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10850. }
  10851. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10852. }
  10853. }
  10854. elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
  10855. {
  10856. foreach ($restrictions as $restriction)
  10857. {
  10858. $restriction_relationship = 'allow';
  10859. $restriction_type = null;
  10860. $restriction_value = 'itunes';
  10861. if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
  10862. {
  10863. $restriction_relationship = 'deny';
  10864. }
  10865. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10866. }
  10867. }
  10868. if (is_array($restrictions_parent))
  10869. {
  10870. $restrictions_parent = array_values(array_unique($restrictions_parent));
  10871. }
  10872. else
  10873. {
  10874. $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
  10875. }
  10876. // THUMBNAILS
  10877. if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
  10878. {
  10879. foreach ($thumbnails as $thumbnail)
  10880. {
  10881. if (isset($thumbnail['attribs']['']['url']))
  10882. {
  10883. $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10884. }
  10885. }
  10886. }
  10887. elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
  10888. {
  10889. foreach ($thumbnails as $thumbnail)
  10890. {
  10891. if (isset($thumbnail['attribs']['']['url']))
  10892. {
  10893. $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10894. }
  10895. }
  10896. }
  10897. // TITLES
  10898. if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
  10899. {
  10900. if (isset($title_parent[0]['data']))
  10901. {
  10902. $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10903. }
  10904. }
  10905. elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
  10906. {
  10907. if (isset($title_parent[0]['data']))
  10908. {
  10909. $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10910. }
  10911. }
  10912. // Clear the memory
  10913. unset($parent);
  10914. // Attributes
  10915. $bitrate = null;
  10916. $channels = null;
  10917. $duration = null;
  10918. $expression = null;
  10919. $framerate = null;
  10920. $height = null;
  10921. $javascript = null;
  10922. $lang = null;
  10923. $length = null;
  10924. $medium = null;
  10925. $samplingrate = null;
  10926. $type = null;
  10927. $url = null;
  10928. $width = null;
  10929. // Elements
  10930. $captions = null;
  10931. $categories = null;
  10932. $copyrights = null;
  10933. $credits = null;
  10934. $description = null;
  10935. $hashes = null;
  10936. $keywords = null;
  10937. $player = null;
  10938. $ratings = null;
  10939. $restrictions = null;
  10940. $thumbnails = null;
  10941. $title = null;
  10942. // If we have media:group tags, loop through them.
  10943. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
  10944. {
  10945. if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
  10946. {
  10947. // If we have media:content tags, loop through them.
  10948. foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
  10949. {
  10950. if (isset($content['attribs']['']['url']))
  10951. {
  10952. // Attributes
  10953. $bitrate = null;
  10954. $channels = null;
  10955. $duration = null;
  10956. $expression = null;
  10957. $framerate = null;
  10958. $height = null;
  10959. $javascript = null;
  10960. $lang = null;
  10961. $length = null;
  10962. $medium = null;
  10963. $samplingrate = null;
  10964. $type = null;
  10965. $url = null;
  10966. $width = null;
  10967. // Elements
  10968. $captions = null;
  10969. $categories = null;
  10970. $copyrights = null;
  10971. $credits = null;
  10972. $description = null;
  10973. $hashes = null;
  10974. $keywords = null;
  10975. $player = null;
  10976. $ratings = null;
  10977. $restrictions = null;
  10978. $thumbnails = null;
  10979. $title = null;
  10980. // Start checking the attributes of media:content
  10981. if (isset($content['attribs']['']['bitrate']))
  10982. {
  10983. $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  10984. }
  10985. if (isset($content['attribs']['']['channels']))
  10986. {
  10987. $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
  10988. }
  10989. if (isset($content['attribs']['']['duration']))
  10990. {
  10991. $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
  10992. }
  10993. else
  10994. {
  10995. $duration = $duration_parent;
  10996. }
  10997. if (isset($content['attribs']['']['expression']))
  10998. {
  10999. $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
  11000. }
  11001. if (isset($content['attribs']['']['framerate']))
  11002. {
  11003. $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11004. }
  11005. if (isset($content['attribs']['']['height']))
  11006. {
  11007. $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
  11008. }
  11009. if (isset($content['attribs']['']['lang']))
  11010. {
  11011. $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11012. }
  11013. if (isset($content['attribs']['']['fileSize']))
  11014. {
  11015. $length = ceil($content['attribs']['']['fileSize']);
  11016. }
  11017. if (isset($content['attribs']['']['medium']))
  11018. {
  11019. $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
  11020. }
  11021. if (isset($content['attribs']['']['samplingrate']))
  11022. {
  11023. $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11024. }
  11025. if (isset($content['attribs']['']['type']))
  11026. {
  11027. $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11028. }
  11029. if (isset($content['attribs']['']['width']))
  11030. {
  11031. $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
  11032. }
  11033. $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11034. // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
  11035. // CAPTIONS
  11036. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  11037. {
  11038. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  11039. {
  11040. $caption_type = null;
  11041. $caption_lang = null;
  11042. $caption_startTime = null;
  11043. $caption_endTime = null;
  11044. $caption_text = null;
  11045. if (isset($caption['attribs']['']['type']))
  11046. {
  11047. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11048. }
  11049. if (isset($caption['attribs']['']['lang']))
  11050. {
  11051. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11052. }
  11053. if (isset($caption['attribs']['']['start']))
  11054. {
  11055. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  11056. }
  11057. if (isset($caption['attribs']['']['end']))
  11058. {
  11059. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  11060. }
  11061. if (isset($caption['data']))
  11062. {
  11063. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11064. }
  11065. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  11066. }
  11067. if (is_array($captions))
  11068. {
  11069. $captions = array_values(array_unique($captions));
  11070. }
  11071. }
  11072. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  11073. {
  11074. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  11075. {
  11076. $caption_type = null;
  11077. $caption_lang = null;
  11078. $caption_startTime = null;
  11079. $caption_endTime = null;
  11080. $caption_text = null;
  11081. if (isset($caption['attribs']['']['type']))
  11082. {
  11083. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11084. }
  11085. if (isset($caption['attribs']['']['lang']))
  11086. {
  11087. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11088. }
  11089. if (isset($caption['attribs']['']['start']))
  11090. {
  11091. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  11092. }
  11093. if (isset($caption['attribs']['']['end']))
  11094. {
  11095. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  11096. }
  11097. if (isset($caption['data']))
  11098. {
  11099. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11100. }
  11101. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  11102. }
  11103. if (is_array($captions))
  11104. {
  11105. $captions = array_values(array_unique($captions));
  11106. }
  11107. }
  11108. else
  11109. {
  11110. $captions = $captions_parent;
  11111. }
  11112. // CATEGORIES
  11113. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  11114. {
  11115. foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  11116. {
  11117. $term = null;
  11118. $scheme = null;
  11119. $label = null;
  11120. if (isset($category['data']))
  11121. {
  11122. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11123. }
  11124. if (isset($category['attribs']['']['scheme']))
  11125. {
  11126. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11127. }
  11128. else
  11129. {
  11130. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  11131. }
  11132. if (isset($category['attribs']['']['label']))
  11133. {
  11134. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  11135. }
  11136. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  11137. }
  11138. }
  11139. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  11140. {
  11141. foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  11142. {
  11143. $term = null;
  11144. $scheme = null;
  11145. $label = null;
  11146. if (isset($category['data']))
  11147. {
  11148. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11149. }
  11150. if (isset($category['attribs']['']['scheme']))
  11151. {
  11152. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11153. }
  11154. else
  11155. {
  11156. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  11157. }
  11158. if (isset($category['attribs']['']['label']))
  11159. {
  11160. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  11161. }
  11162. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  11163. }
  11164. }
  11165. if (is_array($categories) && is_array($categories_parent))
  11166. {
  11167. $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
  11168. }
  11169. elseif (is_array($categories))
  11170. {
  11171. $categories = array_values(array_unique($categories));
  11172. }
  11173. elseif (is_array($categories_parent))
  11174. {
  11175. $categories = array_values(array_unique($categories_parent));
  11176. }
  11177. // COPYRIGHTS
  11178. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  11179. {
  11180. $copyright_url = null;
  11181. $copyright_label = null;
  11182. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  11183. {
  11184. $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  11185. }
  11186. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  11187. {
  11188. $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11189. }
  11190. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  11191. }
  11192. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  11193. {
  11194. $copyright_url = null;
  11195. $copyright_label = null;
  11196. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  11197. {
  11198. $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  11199. }
  11200. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  11201. {
  11202. $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11203. }
  11204. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  11205. }
  11206. else
  11207. {
  11208. $copyrights = $copyrights_parent;
  11209. }
  11210. // CREDITS
  11211. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  11212. {
  11213. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  11214. {
  11215. $credit_role = null;
  11216. $credit_scheme = null;
  11217. $credit_name = null;
  11218. if (isset($credit['attribs']['']['role']))
  11219. {
  11220. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  11221. }
  11222. if (isset($credit['attribs']['']['scheme']))
  11223. {
  11224. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11225. }
  11226. else
  11227. {
  11228. $credit_scheme = 'urn:ebu';
  11229. }
  11230. if (isset($credit['data']))
  11231. {
  11232. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11233. }
  11234. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  11235. }
  11236. if (is_array($credits))
  11237. {
  11238. $credits = array_values(array_unique($credits));
  11239. }
  11240. }
  11241. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  11242. {
  11243. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  11244. {
  11245. $credit_role = null;
  11246. $credit_scheme = null;
  11247. $credit_name = null;
  11248. if (isset($credit['attribs']['']['role']))
  11249. {
  11250. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  11251. }
  11252. if (isset($credit['attribs']['']['scheme']))
  11253. {
  11254. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11255. }
  11256. else
  11257. {
  11258. $credit_scheme = 'urn:ebu';
  11259. }
  11260. if (isset($credit['data']))
  11261. {
  11262. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11263. }
  11264. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  11265. }
  11266. if (is_array($credits))
  11267. {
  11268. $credits = array_values(array_unique($credits));
  11269. }
  11270. }
  11271. else
  11272. {
  11273. $credits = $credits_parent;
  11274. }
  11275. // DESCRIPTION
  11276. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  11277. {
  11278. $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11279. }
  11280. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  11281. {
  11282. $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11283. }
  11284. else
  11285. {
  11286. $description = $description_parent;
  11287. }
  11288. // HASHES
  11289. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  11290. {
  11291. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  11292. {
  11293. $value = null;
  11294. $algo = null;
  11295. if (isset($hash['data']))
  11296. {
  11297. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11298. }
  11299. if (isset($hash['attribs']['']['algo']))
  11300. {
  11301. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  11302. }
  11303. else
  11304. {
  11305. $algo = 'md5';
  11306. }
  11307. $hashes[] = $algo.':'.$value;
  11308. }
  11309. if (is_array($hashes))
  11310. {
  11311. $hashes = array_values(array_unique($hashes));
  11312. }
  11313. }
  11314. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  11315. {
  11316. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  11317. {
  11318. $value = null;
  11319. $algo = null;
  11320. if (isset($hash['data']))
  11321. {
  11322. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11323. }
  11324. if (isset($hash['attribs']['']['algo']))
  11325. {
  11326. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  11327. }
  11328. else
  11329. {
  11330. $algo = 'md5';
  11331. }
  11332. $hashes[] = $algo.':'.$value;
  11333. }
  11334. if (is_array($hashes))
  11335. {
  11336. $hashes = array_values(array_unique($hashes));
  11337. }
  11338. }
  11339. else
  11340. {
  11341. $hashes = $hashes_parent;
  11342. }
  11343. // KEYWORDS
  11344. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  11345. {
  11346. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  11347. {
  11348. $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  11349. foreach ($temp as $word)
  11350. {
  11351. $keywords[] = trim($word);
  11352. }
  11353. unset($temp);
  11354. }
  11355. if (is_array($keywords))
  11356. {
  11357. $keywords = array_values(array_unique($keywords));
  11358. }
  11359. }
  11360. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  11361. {
  11362. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  11363. {
  11364. $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  11365. foreach ($temp as $word)
  11366. {
  11367. $keywords[] = trim($word);
  11368. }
  11369. unset($temp);
  11370. }
  11371. if (is_array($keywords))
  11372. {
  11373. $keywords = array_values(array_unique($keywords));
  11374. }
  11375. }
  11376. else
  11377. {
  11378. $keywords = $keywords_parent;
  11379. }
  11380. // PLAYER
  11381. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  11382. {
  11383. $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11384. }
  11385. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  11386. {
  11387. $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11388. }
  11389. else
  11390. {
  11391. $player = $player_parent;
  11392. }
  11393. // RATINGS
  11394. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  11395. {
  11396. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  11397. {
  11398. $rating_scheme = null;
  11399. $rating_value = null;
  11400. if (isset($rating['attribs']['']['scheme']))
  11401. {
  11402. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11403. }
  11404. else
  11405. {
  11406. $rating_scheme = 'urn:simple';
  11407. }
  11408. if (isset($rating['data']))
  11409. {
  11410. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11411. }
  11412. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  11413. }
  11414. if (is_array($ratings))
  11415. {
  11416. $ratings = array_values(array_unique($ratings));
  11417. }
  11418. }
  11419. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  11420. {
  11421. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  11422. {
  11423. $rating_scheme = null;
  11424. $rating_value = null;
  11425. if (isset($rating['attribs']['']['scheme']))
  11426. {
  11427. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11428. }
  11429. else
  11430. {
  11431. $rating_scheme = 'urn:simple';
  11432. }
  11433. if (isset($rating['data']))
  11434. {
  11435. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11436. }
  11437. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  11438. }
  11439. if (is_array($ratings))
  11440. {
  11441. $ratings = array_values(array_unique($ratings));
  11442. }
  11443. }
  11444. else
  11445. {
  11446. $ratings = $ratings_parent;
  11447. }
  11448. // RESTRICTIONS
  11449. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  11450. {
  11451. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  11452. {
  11453. $restriction_relationship = null;
  11454. $restriction_type = null;
  11455. $restriction_value = null;
  11456. if (isset($restriction['attribs']['']['relationship']))
  11457. {
  11458. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  11459. }
  11460. if (isset($restriction['attribs']['']['type']))
  11461. {
  11462. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11463. }
  11464. if (isset($restriction['data']))
  11465. {
  11466. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11467. }
  11468. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  11469. }
  11470. if (is_array($restrictions))
  11471. {
  11472. $restrictions = array_values(array_unique($restrictions));
  11473. }
  11474. }
  11475. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  11476. {
  11477. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  11478. {
  11479. $restriction_relationship = null;
  11480. $restriction_type = null;
  11481. $restriction_value = null;
  11482. if (isset($restriction['attribs']['']['relationship']))
  11483. {
  11484. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  11485. }
  11486. if (isset($restriction['attribs']['']['type']))
  11487. {
  11488. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11489. }
  11490. if (isset($restriction['data']))
  11491. {
  11492. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11493. }
  11494. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  11495. }
  11496. if (is_array($restrictions))
  11497. {
  11498. $restrictions = array_values(array_unique($restrictions));
  11499. }
  11500. }
  11501. else
  11502. {
  11503. $restrictions = $restrictions_parent;
  11504. }
  11505. // THUMBNAILS
  11506. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  11507. {
  11508. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  11509. {
  11510. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11511. }
  11512. if (is_array($thumbnails))
  11513. {
  11514. $thumbnails = array_values(array_unique($thumbnails));
  11515. }
  11516. }
  11517. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  11518. {
  11519. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  11520. {
  11521. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11522. }
  11523. if (is_array($thumbnails))
  11524. {
  11525. $thumbnails = array_values(array_unique($thumbnails));
  11526. }
  11527. }
  11528. else
  11529. {
  11530. $thumbnails = $thumbnails_parent;
  11531. }
  11532. // TITLES
  11533. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  11534. {
  11535. $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11536. }
  11537. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  11538. {
  11539. $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11540. }
  11541. else
  11542. {
  11543. $title = $title_parent;
  11544. }
  11545. $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
  11546. }
  11547. }
  11548. }
  11549. }
  11550. // If we have standalone media:content tags, loop through them.
  11551. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
  11552. {
  11553. foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
  11554. {
  11555. if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  11556. {
  11557. // Attributes
  11558. $bitrate = null;
  11559. $channels = null;
  11560. $duration = null;
  11561. $expression = null;
  11562. $framerate = null;
  11563. $height = null;
  11564. $javascript = null;
  11565. $lang = null;
  11566. $length = null;
  11567. $medium = null;
  11568. $samplingrate = null;
  11569. $type = null;
  11570. $url = null;
  11571. $width = null;
  11572. // Elements
  11573. $captions = null;
  11574. $categories = null;
  11575. $copyrights = null;
  11576. $credits = null;
  11577. $description = null;
  11578. $hashes = null;
  11579. $keywords = null;
  11580. $player = null;
  11581. $ratings = null;
  11582. $restrictions = null;
  11583. $thumbnails = null;
  11584. $title = null;
  11585. // Start checking the attributes of media:content
  11586. if (isset($content['attribs']['']['bitrate']))
  11587. {
  11588. $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11589. }
  11590. if (isset($content['attribs']['']['channels']))
  11591. {
  11592. $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
  11593. }
  11594. if (isset($content['attribs']['']['duration']))
  11595. {
  11596. $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
  11597. }
  11598. else
  11599. {
  11600. $duration = $duration_parent;
  11601. }
  11602. if (isset($content['attribs']['']['expression']))
  11603. {
  11604. $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
  11605. }
  11606. if (isset($content['attribs']['']['framerate']))
  11607. {
  11608. $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11609. }
  11610. if (isset($content['attribs']['']['height']))
  11611. {
  11612. $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
  11613. }
  11614. if (isset($content['attribs']['']['lang']))
  11615. {
  11616. $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11617. }
  11618. if (isset($content['attribs']['']['fileSize']))
  11619. {
  11620. $length = ceil($content['attribs']['']['fileSize']);
  11621. }
  11622. if (isset($content['attribs']['']['medium']))
  11623. {
  11624. $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
  11625. }
  11626. if (isset($content['attribs']['']['samplingrate']))
  11627. {
  11628. $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11629. }
  11630. if (isset($content['attribs']['']['type']))
  11631. {
  11632. $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11633. }
  11634. if (isset($content['attribs']['']['width']))
  11635. {
  11636. $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
  11637. }
  11638. if (isset($content['attribs']['']['url']))
  11639. {
  11640. $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11641. }
  11642. // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
  11643. // CAPTIONS
  11644. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  11645. {
  11646. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  11647. {
  11648. $caption_type = null;
  11649. $caption_lang = null;
  11650. $caption_startTime = null;
  11651. $caption_endTime = null;
  11652. $caption_text = null;
  11653. if (isset($caption['attribs']['']['type']))
  11654. {
  11655. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11656. }
  11657. if (isset($caption['attribs']['']['lang']))
  11658. {
  11659. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11660. }
  11661. if (isset($caption['attribs']['']['start']))
  11662. {
  11663. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  11664. }
  11665. if (isset($caption['attribs']['']['end']))
  11666. {
  11667. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  11668. }
  11669. if (isset($caption['data']))
  11670. {
  11671. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11672. }
  11673. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  11674. }
  11675. if (is_array($captions))
  11676. {
  11677. $captions = array_values(array_unique($captions));
  11678. }
  11679. }
  11680. else
  11681. {
  11682. $captions = $captions_parent;
  11683. }
  11684. // CATEGORIES
  11685. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  11686. {
  11687. foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  11688. {
  11689. $term = null;
  11690. $scheme = null;
  11691. $label = null;
  11692. if (isset($category['data']))
  11693. {
  11694. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11695. }
  11696. if (isset($category['attribs']['']['scheme']))
  11697. {
  11698. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11699. }
  11700. else
  11701. {
  11702. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  11703. }
  11704. if (isset($category['attribs']['']['label']))
  11705. {
  11706. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  11707. }
  11708. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  11709. }
  11710. }
  11711. if (is_array($categories) && is_array($categories_parent))
  11712. {
  11713. $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
  11714. }
  11715. elseif (is_array($categories))
  11716. {
  11717. $categories = array_values(array_unique($categories));
  11718. }
  11719. elseif (is_array($categories_parent))
  11720. {
  11721. $categories = array_values(array_unique($categories_parent));
  11722. }
  11723. else
  11724. {
  11725. $categories = null;
  11726. }
  11727. // COPYRIGHTS
  11728. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  11729. {
  11730. $copyright_url = null;
  11731. $copyright_label = null;
  11732. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  11733. {
  11734. $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  11735. }
  11736. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  11737. {
  11738. $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11739. }
  11740. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  11741. }
  11742. else
  11743. {
  11744. $copyrights = $copyrights_parent;
  11745. }
  11746. // CREDITS
  11747. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  11748. {
  11749. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  11750. {
  11751. $credit_role = null;
  11752. $credit_scheme = null;
  11753. $credit_name = null;
  11754. if (isset($credit['attribs']['']['role']))
  11755. {
  11756. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  11757. }
  11758. if (isset($credit['attribs']['']['scheme']))
  11759. {
  11760. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11761. }
  11762. else
  11763. {
  11764. $credit_scheme = 'urn:ebu';
  11765. }
  11766. if (isset($credit['data']))
  11767. {
  11768. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11769. }
  11770. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  11771. }
  11772. if (is_array($credits))
  11773. {
  11774. $credits = array_values(array_unique($credits));
  11775. }
  11776. }
  11777. else
  11778. {
  11779. $credits = $credits_parent;
  11780. }
  11781. // DESCRIPTION
  11782. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  11783. {
  11784. $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11785. }
  11786. else
  11787. {
  11788. $description = $description_parent;
  11789. }
  11790. // HASHES
  11791. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  11792. {
  11793. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  11794. {
  11795. $value = null;
  11796. $algo = null;
  11797. if (isset($hash['data']))
  11798. {
  11799. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11800. }
  11801. if (isset($hash['attribs']['']['algo']))
  11802. {
  11803. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  11804. }
  11805. else
  11806. {
  11807. $algo = 'md5';
  11808. }
  11809. $hashes[] = $algo.':'.$value;
  11810. }
  11811. if (is_array($hashes))
  11812. {
  11813. $hashes = array_values(array_unique($hashes));
  11814. }
  11815. }
  11816. else
  11817. {
  11818. $hashes = $hashes_parent;
  11819. }
  11820. // KEYWORDS
  11821. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  11822. {
  11823. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  11824. {
  11825. $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  11826. foreach ($temp as $word)
  11827. {
  11828. $keywords[] = trim($word);
  11829. }
  11830. unset($temp);
  11831. }
  11832. if (is_array($keywords))
  11833. {
  11834. $keywords = array_values(array_unique($keywords));
  11835. }
  11836. }
  11837. else
  11838. {
  11839. $keywords = $keywords_parent;
  11840. }
  11841. // PLAYER
  11842. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  11843. {
  11844. $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11845. }
  11846. else
  11847. {
  11848. $player = $player_parent;
  11849. }
  11850. // RATINGS
  11851. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  11852. {
  11853. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  11854. {
  11855. $rating_scheme = null;
  11856. $rating_value = null;
  11857. if (isset($rating['attribs']['']['scheme']))
  11858. {
  11859. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11860. }
  11861. else
  11862. {
  11863. $rating_scheme = 'urn:simple';
  11864. }
  11865. if (isset($rating['data']))
  11866. {
  11867. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11868. }
  11869. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  11870. }
  11871. if (is_array($ratings))
  11872. {
  11873. $ratings = array_values(array_unique($ratings));
  11874. }
  11875. }
  11876. else
  11877. {
  11878. $ratings = $ratings_parent;
  11879. }
  11880. // RESTRICTIONS
  11881. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  11882. {
  11883. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  11884. {
  11885. $restriction_relationship = null;
  11886. $restriction_type = null;
  11887. $restriction_value = null;
  11888. if (isset($restriction['attribs']['']['relationship']))
  11889. {
  11890. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  11891. }
  11892. if (isset($restriction['attribs']['']['type']))
  11893. {
  11894. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11895. }
  11896. if (isset($restriction['data']))
  11897. {
  11898. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11899. }
  11900. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  11901. }
  11902. if (is_array($restrictions))
  11903. {
  11904. $restrictions = array_values(array_unique($restrictions));
  11905. }
  11906. }
  11907. else
  11908. {
  11909. $restrictions = $restrictions_parent;
  11910. }
  11911. // THUMBNAILS
  11912. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  11913. {
  11914. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  11915. {
  11916. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11917. }
  11918. if (is_array($thumbnails))
  11919. {
  11920. $thumbnails = array_values(array_unique($thumbnails));
  11921. }
  11922. }
  11923. else
  11924. {
  11925. $thumbnails = $thumbnails_parent;
  11926. }
  11927. // TITLES
  11928. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  11929. {
  11930. $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11931. }
  11932. else
  11933. {
  11934. $title = $title_parent;
  11935. }
  11936. $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
  11937. }
  11938. }
  11939. }
  11940. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  11941. {
  11942. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  11943. {
  11944. // Attributes
  11945. $bitrate = null;
  11946. $channels = null;
  11947. $duration = null;
  11948. $expression = null;
  11949. $framerate = null;
  11950. $height = null;
  11951. $javascript = null;
  11952. $lang = null;
  11953. $length = null;
  11954. $medium = null;
  11955. $samplingrate = null;
  11956. $type = null;
  11957. $url = null;
  11958. $width = null;
  11959. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  11960. if (isset($link['attribs']['']['type']))
  11961. {
  11962. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11963. }
  11964. if (isset($link['attribs']['']['length']))
  11965. {
  11966. $length = ceil($link['attribs']['']['length']);
  11967. }
  11968. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  11969. $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
  11970. }
  11971. }
  11972. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  11973. {
  11974. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  11975. {
  11976. // Attributes
  11977. $bitrate = null;
  11978. $channels = null;
  11979. $duration = null;
  11980. $expression = null;
  11981. $framerate = null;
  11982. $height = null;
  11983. $javascript = null;
  11984. $lang = null;
  11985. $length = null;
  11986. $medium = null;
  11987. $samplingrate = null;
  11988. $type = null;
  11989. $url = null;
  11990. $width = null;
  11991. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  11992. if (isset($link['attribs']['']['type']))
  11993. {
  11994. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11995. }
  11996. if (isset($link['attribs']['']['length']))
  11997. {
  11998. $length = ceil($link['attribs']['']['length']);
  11999. }
  12000. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  12001. $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
  12002. }
  12003. }
  12004. if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
  12005. {
  12006. if (isset($enclosure[0]['attribs']['']['url']))
  12007. {
  12008. // Attributes
  12009. $bitrate = null;
  12010. $channels = null;
  12011. $duration = null;
  12012. $expression = null;
  12013. $framerate = null;
  12014. $height = null;
  12015. $javascript = null;
  12016. $lang = null;
  12017. $length = null;
  12018. $medium = null;
  12019. $samplingrate = null;
  12020. $type = null;
  12021. $url = null;
  12022. $width = null;
  12023. $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
  12024. if (isset($enclosure[0]['attribs']['']['type']))
  12025. {
  12026. $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  12027. }
  12028. if (isset($enclosure[0]['attribs']['']['length']))
  12029. {
  12030. $length = ceil($enclosure[0]['attribs']['']['length']);
  12031. }
  12032. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  12033. $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
  12034. }
  12035. }
  12036. if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
  12037. {
  12038. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  12039. $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
  12040. }
  12041. $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
  12042. }
  12043. if (!empty($this->data['enclosures']))
  12044. {
  12045. return $this->data['enclosures'];
  12046. }
  12047. else
  12048. {
  12049. return null;
  12050. }
  12051. }
  12052. /**
  12053. * Get the latitude coordinates for the item
  12054. *
  12055. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  12056. *
  12057. * Uses `<geo:lat>` or `<georss:point>`
  12058. *
  12059. * @since 1.0
  12060. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  12061. * @link http://www.georss.org/ GeoRSS
  12062. * @return string|null
  12063. */
  12064. public function get_latitude()
  12065. {
  12066. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  12067. {
  12068. return (float) $return[0]['data'];
  12069. }
  12070. elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
  12071. {
  12072. return (float) $match[1];
  12073. }
  12074. else
  12075. {
  12076. return null;
  12077. }
  12078. }
  12079. /**
  12080. * Get the longitude coordinates for the item
  12081. *
  12082. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  12083. *
  12084. * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
  12085. *
  12086. * @since 1.0
  12087. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  12088. * @link http://www.georss.org/ GeoRSS
  12089. * @return string|null
  12090. */
  12091. public function get_longitude()
  12092. {
  12093. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  12094. {
  12095. return (float) $return[0]['data'];
  12096. }
  12097. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  12098. {
  12099. return (float) $return[0]['data'];
  12100. }
  12101. elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
  12102. {
  12103. return (float) $match[2];
  12104. }
  12105. else
  12106. {
  12107. return null;
  12108. }
  12109. }
  12110. /**
  12111. * Get the `<atom:source>` for the item
  12112. *
  12113. * @since 1.1
  12114. * @return SimplePie_Source|null
  12115. */
  12116. public function get_source()
  12117. {
  12118. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
  12119. {
  12120. return $this->registry->create('Source', array($this, $return[0]));
  12121. }
  12122. else
  12123. {
  12124. return null;
  12125. }
  12126. }
  12127. }
  12128. /**
  12129. * Decode 'gzip' encoded HTTP data
  12130. *
  12131. * @package SimplePie
  12132. * @subpackage HTTP
  12133. * @link http://www.gzip.org/format.txt
  12134. */
  12135. class SimplePie_gzdecode
  12136. {
  12137. /**
  12138. * Compressed data
  12139. *
  12140. * @access private
  12141. * @var string
  12142. * @see gzdecode::$data
  12143. */
  12144. var $compressed_data;
  12145. /**
  12146. * Size of compressed data
  12147. *
  12148. * @access private
  12149. * @var int
  12150. */
  12151. var $compressed_size;
  12152. /**
  12153. * Minimum size of a valid gzip string
  12154. *
  12155. * @access private
  12156. * @var int
  12157. */
  12158. var $min_compressed_size = 18;
  12159. /**
  12160. * Current position of pointer
  12161. *
  12162. * @access private
  12163. * @var int
  12164. */
  12165. var $position = 0;
  12166. /**
  12167. * Flags (FLG)
  12168. *
  12169. * @access private
  12170. * @var int
  12171. */
  12172. var $flags;
  12173. /**
  12174. * Uncompressed data
  12175. *
  12176. * @access public
  12177. * @see gzdecode::$compressed_data
  12178. * @var string
  12179. */
  12180. var $data;
  12181. /**
  12182. * Modified time
  12183. *
  12184. * @access public
  12185. * @var int
  12186. */
  12187. var $MTIME;
  12188. /**
  12189. * Extra Flags
  12190. *
  12191. * @access public
  12192. * @var int
  12193. */
  12194. var $XFL;
  12195. /**
  12196. * Operating System
  12197. *
  12198. * @access public
  12199. * @var int
  12200. */
  12201. var $OS;
  12202. /**
  12203. * Subfield ID 1
  12204. *
  12205. * @access public
  12206. * @see gzdecode::$extra_field
  12207. * @see gzdecode::$SI2
  12208. * @var string
  12209. */
  12210. var $SI1;
  12211. /**
  12212. * Subfield ID 2
  12213. *
  12214. * @access public
  12215. * @see gzdecode::$extra_field
  12216. * @see gzdecode::$SI1
  12217. * @var string
  12218. */
  12219. var $SI2;
  12220. /**
  12221. * Extra field content
  12222. *
  12223. * @access public
  12224. * @see gzdecode::$SI1
  12225. * @see gzdecode::$SI2
  12226. * @var string
  12227. */
  12228. var $extra_field;
  12229. /**
  12230. * Original filename
  12231. *
  12232. * @access public
  12233. * @var string
  12234. */
  12235. var $filename;
  12236. /**
  12237. * Human readable comment
  12238. *
  12239. * @access public
  12240. * @var string
  12241. */
  12242. var $comment;
  12243. /**
  12244. * Don't allow anything to be set
  12245. *
  12246. * @param string $name
  12247. * @param mixed $value
  12248. */
  12249. public function __set($name, $value)
  12250. {
  12251. trigger_error("Cannot write property $name", E_USER_ERROR);
  12252. }
  12253. /**
  12254. * Set the compressed string and related properties
  12255. *
  12256. * @param string $data
  12257. */
  12258. public function __construct($data)
  12259. {
  12260. $this->compressed_data = $data;
  12261. $this->compressed_size = strlen($data);
  12262. }
  12263. /**
  12264. * Decode the GZIP stream
  12265. *
  12266. * @return bool Successfulness
  12267. */
  12268. public function parse()
  12269. {
  12270. if ($this->compressed_size >= $this->min_compressed_size)
  12271. {
  12272. // Check ID1, ID2, and CM
  12273. if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
  12274. {
  12275. return false;
  12276. }
  12277. // Get the FLG (FLaGs)
  12278. $this->flags = ord($this->compressed_data[3]);
  12279. // FLG bits above (1 << 4) are reserved
  12280. if ($this->flags > 0x1F)
  12281. {
  12282. return false;
  12283. }
  12284. // Advance the pointer after the above
  12285. $this->position += 4;
  12286. // MTIME
  12287. $mtime = substr($this->compressed_data, $this->position, 4);
  12288. // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
  12289. if (current(unpack('S', "\x00\x01")) === 1)
  12290. {
  12291. $mtime = strrev($mtime);
  12292. }
  12293. $this->MTIME = current(unpack('l', $mtime));
  12294. $this->position += 4;
  12295. // Get the XFL (eXtra FLags)
  12296. $this->XFL = ord($this->compressed_data[$this->position++]);
  12297. // Get the OS (Operating System)
  12298. $this->OS = ord($this->compressed_data[$this->position++]);
  12299. // Parse the FEXTRA
  12300. if ($this->flags & 4)
  12301. {
  12302. // Read subfield IDs
  12303. $this->SI1 = $this->compressed_data[$this->position++];
  12304. $this->SI2 = $this->compressed_data[$this->position++];
  12305. // SI2 set to zero is reserved for future use
  12306. if ($this->SI2 === "\x00")
  12307. {
  12308. return false;
  12309. }
  12310. // Get the length of the extra field
  12311. $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  12312. $this->position += 2;
  12313. // Check the length of the string is still valid
  12314. $this->min_compressed_size += $len + 4;
  12315. if ($this->compressed_size >= $this->min_compressed_size)
  12316. {
  12317. // Set the extra field to the given data
  12318. $this->extra_field = substr($this->compressed_data, $this->position, $len);
  12319. $this->position += $len;
  12320. }
  12321. else
  12322. {
  12323. return false;
  12324. }
  12325. }
  12326. // Parse the FNAME
  12327. if ($this->flags & 8)
  12328. {
  12329. // Get the length of the filename
  12330. $len = strcspn($this->compressed_data, "\x00", $this->position);
  12331. // Check the length of the string is still valid
  12332. $this->min_compressed_size += $len + 1;
  12333. if ($this->compressed_size >= $this->min_compressed_size)
  12334. {
  12335. // Set the original filename to the given string
  12336. $this->filename = substr($this->compressed_data, $this->position, $len);
  12337. $this->position += $len + 1;
  12338. }
  12339. else
  12340. {
  12341. return false;
  12342. }
  12343. }
  12344. // Parse the FCOMMENT
  12345. if ($this->flags & 16)
  12346. {
  12347. // Get the length of the comment
  12348. $len = strcspn($this->compressed_data, "\x00", $this->position);
  12349. // Check the length of the string is still valid
  12350. $this->min_compressed_size += $len + 1;
  12351. if ($this->compressed_size >= $this->min_compressed_size)
  12352. {
  12353. // Set the original comment to the given string
  12354. $this->comment = substr($this->compressed_data, $this->position, $len);
  12355. $this->position += $len + 1;
  12356. }
  12357. else
  12358. {
  12359. return false;
  12360. }
  12361. }
  12362. // Parse the FHCRC
  12363. if ($this->flags & 2)
  12364. {
  12365. // Check the length of the string is still valid
  12366. $this->min_compressed_size += $len + 2;
  12367. if ($this->compressed_size >= $this->min_compressed_size)
  12368. {
  12369. // Read the CRC
  12370. $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  12371. // Check the CRC matches
  12372. if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
  12373. {
  12374. $this->position += 2;
  12375. }
  12376. else
  12377. {
  12378. return false;
  12379. }
  12380. }
  12381. else
  12382. {
  12383. return false;
  12384. }
  12385. }
  12386. // Decompress the actual data
  12387. if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
  12388. {
  12389. return false;
  12390. }
  12391. else
  12392. {
  12393. $this->position = $this->compressed_size - 8;
  12394. }
  12395. // Check CRC of data
  12396. $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  12397. $this->position += 4;
  12398. /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
  12399. {
  12400. return false;
  12401. }*/
  12402. // Check ISIZE of data
  12403. $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  12404. $this->position += 4;
  12405. if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
  12406. {
  12407. return false;
  12408. }
  12409. // Wow, against all odds, we've actually got a valid gzip string
  12410. return true;
  12411. }
  12412. else
  12413. {
  12414. return false;
  12415. }
  12416. }
  12417. }
  12418. /**
  12419. * HTTP Response Parser
  12420. *
  12421. * @package SimplePie
  12422. * @subpackage HTTP
  12423. */
  12424. class SimplePie_HTTP_Parser
  12425. {
  12426. /**
  12427. * HTTP Version
  12428. *
  12429. * @var float
  12430. */
  12431. public $http_version = 0.0;
  12432. /**
  12433. * Status code
  12434. *
  12435. * @var int
  12436. */
  12437. public $status_code = 0;
  12438. /**
  12439. * Reason phrase
  12440. *
  12441. * @var string
  12442. */
  12443. public $reason = '';
  12444. /**
  12445. * Key/value pairs of the headers
  12446. *
  12447. * @var array
  12448. */
  12449. public $headers = array();
  12450. /**
  12451. * Body of the response
  12452. *
  12453. * @var string
  12454. */
  12455. public $body = '';
  12456. /**
  12457. * Current state of the state machine
  12458. *
  12459. * @var string
  12460. */
  12461. protected $state = 'http_version';
  12462. /**
  12463. * Input data
  12464. *
  12465. * @var string
  12466. */
  12467. protected $data = '';
  12468. /**
  12469. * Input data length (to avoid calling strlen() everytime this is needed)
  12470. *
  12471. * @var int
  12472. */
  12473. protected $data_length = 0;
  12474. /**
  12475. * Current position of the pointer
  12476. *
  12477. * @var int
  12478. */
  12479. protected $position = 0;
  12480. /**
  12481. * Name of the hedaer currently being parsed
  12482. *
  12483. * @var string
  12484. */
  12485. protected $name = '';
  12486. /**
  12487. * Value of the hedaer currently being parsed
  12488. *
  12489. * @var string
  12490. */
  12491. protected $value = '';
  12492. /**
  12493. * Create an instance of the class with the input data
  12494. *
  12495. * @param string $data Input data
  12496. */
  12497. public function __construct($data)
  12498. {
  12499. $this->data = $data;
  12500. $this->data_length = strlen($this->data);
  12501. }
  12502. /**
  12503. * Parse the input data
  12504. *
  12505. * @return bool true on success, false on failure
  12506. */
  12507. public function parse()
  12508. {
  12509. while ($this->state && $this->state !== 'emit' && $this->has_data())
  12510. {
  12511. $state = $this->state;
  12512. $this->$state();
  12513. }
  12514. $this->data = '';
  12515. if ($this->state === 'emit' || $this->state === 'body')
  12516. {
  12517. return true;
  12518. }
  12519. else
  12520. {
  12521. $this->http_version = '';
  12522. $this->status_code = '';
  12523. $this->reason = '';
  12524. $this->headers = array();
  12525. $this->body = '';
  12526. return false;
  12527. }
  12528. }
  12529. /**
  12530. * Check whether there is data beyond the pointer
  12531. *
  12532. * @return bool true if there is further data, false if not
  12533. */
  12534. protected function has_data()
  12535. {
  12536. return (bool) ($this->position < $this->data_length);
  12537. }
  12538. /**
  12539. * See if the next character is LWS
  12540. *
  12541. * @return bool true if the next character is LWS, false if not
  12542. */
  12543. protected function is_linear_whitespace()
  12544. {
  12545. return (bool) ($this->data[$this->position] === "\x09"
  12546. || $this->data[$this->position] === "\x20"
  12547. || ($this->data[$this->position] === "\x0A"
  12548. && isset($this->data[$this->position + 1])
  12549. && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
  12550. }
  12551. /**
  12552. * Parse the HTTP version
  12553. */
  12554. protected function http_version()
  12555. {
  12556. if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
  12557. {
  12558. $len = strspn($this->data, '0123456789.', 5);
  12559. $this->http_version = substr($this->data, 5, $len);
  12560. $this->position += 5 + $len;
  12561. if (substr_count($this->http_version, '.') <= 1)
  12562. {
  12563. $this->http_version = (float) $this->http_version;
  12564. $this->position += strspn($this->data, "\x09\x20", $this->position);
  12565. $this->state = 'status';
  12566. }
  12567. else
  12568. {
  12569. $this->state = false;
  12570. }
  12571. }
  12572. else
  12573. {
  12574. $this->state = false;
  12575. }
  12576. }
  12577. /**
  12578. * Parse the status code
  12579. */
  12580. protected function status()
  12581. {
  12582. if ($len = strspn($this->data, '0123456789', $this->position))
  12583. {
  12584. $this->status_code = (int) substr($this->data, $this->position, $len);
  12585. $this->position += $len;
  12586. $this->state = 'reason';
  12587. }
  12588. else
  12589. {
  12590. $this->state = false;
  12591. }
  12592. }
  12593. /**
  12594. * Parse the reason phrase
  12595. */
  12596. protected function reason()
  12597. {
  12598. $len = strcspn($this->data, "\x0A", $this->position);
  12599. $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
  12600. $this->position += $len + 1;
  12601. $this->state = 'new_line';
  12602. }
  12603. /**
  12604. * Deal with a new line, shifting data around as needed
  12605. */
  12606. protected function new_line()
  12607. {
  12608. $this->value = trim($this->value, "\x0D\x20");
  12609. if ($this->name !== '' && $this->value !== '')
  12610. {
  12611. $this->name = strtolower($this->name);
  12612. // We should only use the last Content-Type header. c.f. issue #1
  12613. if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
  12614. {
  12615. $this->headers[$this->name] .= ', ' . $this->value;
  12616. }
  12617. else
  12618. {
  12619. $this->headers[$this->name] = $this->value;
  12620. }
  12621. }
  12622. $this->name = '';
  12623. $this->value = '';
  12624. if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
  12625. {
  12626. $this->position += 2;
  12627. $this->state = 'body';
  12628. }
  12629. elseif ($this->data[$this->position] === "\x0A")
  12630. {
  12631. $this->position++;
  12632. $this->state = 'body';
  12633. }
  12634. else
  12635. {
  12636. $this->state = 'name';
  12637. }
  12638. }
  12639. /**
  12640. * Parse a header name
  12641. */
  12642. protected function name()
  12643. {
  12644. $len = strcspn($this->data, "\x0A:", $this->position);
  12645. if (isset($this->data[$this->position + $len]))
  12646. {
  12647. if ($this->data[$this->position + $len] === "\x0A")
  12648. {
  12649. $this->position += $len;
  12650. $this->state = 'new_line';
  12651. }
  12652. else
  12653. {
  12654. $this->name = substr($this->data, $this->position, $len);
  12655. $this->position += $len + 1;
  12656. $this->state = 'value';
  12657. }
  12658. }
  12659. else
  12660. {
  12661. $this->state = false;
  12662. }
  12663. }
  12664. /**
  12665. * Parse LWS, replacing consecutive LWS characters with a single space
  12666. */
  12667. protected function linear_whitespace()
  12668. {
  12669. do
  12670. {
  12671. if (substr($this->data, $this->position, 2) === "\x0D\x0A")
  12672. {
  12673. $this->position += 2;
  12674. }
  12675. elseif ($this->data[$this->position] === "\x0A")
  12676. {
  12677. $this->position++;
  12678. }
  12679. $this->position += strspn($this->data, "\x09\x20", $this->position);
  12680. } while ($this->has_data() && $this->is_linear_whitespace());
  12681. $this->value .= "\x20";
  12682. }
  12683. /**
  12684. * See what state to move to while within non-quoted header values
  12685. */
  12686. protected function value()
  12687. {
  12688. if ($this->is_linear_whitespace())
  12689. {
  12690. $this->linear_whitespace();
  12691. }
  12692. else
  12693. {
  12694. switch ($this->data[$this->position])
  12695. {
  12696. case '"':
  12697. // Workaround for ETags: we have to include the quotes as
  12698. // part of the tag.
  12699. if (strtolower($this->name) === 'etag')
  12700. {
  12701. $this->value .= '"';
  12702. $this->position++;
  12703. $this->state = 'value_char';
  12704. break;
  12705. }
  12706. $this->position++;
  12707. $this->state = 'quote';
  12708. break;
  12709. case "\x0A":
  12710. $this->position++;
  12711. $this->state = 'new_line';
  12712. break;
  12713. default:
  12714. $this->state = 'value_char';
  12715. break;
  12716. }
  12717. }
  12718. }
  12719. /**
  12720. * Parse a header value while outside quotes
  12721. */
  12722. protected function value_char()
  12723. {
  12724. $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
  12725. $this->value .= substr($this->data, $this->position, $len);
  12726. $this->position += $len;
  12727. $this->state = 'value';
  12728. }
  12729. /**
  12730. * See what state to move to while within quoted header values
  12731. */
  12732. protected function quote()
  12733. {
  12734. if ($this->is_linear_whitespace())
  12735. {
  12736. $this->linear_whitespace();
  12737. }
  12738. else
  12739. {
  12740. switch ($this->data[$this->position])
  12741. {
  12742. case '"':
  12743. $this->position++;
  12744. $this->state = 'value';
  12745. break;
  12746. case "\x0A":
  12747. $this->position++;
  12748. $this->state = 'new_line';
  12749. break;
  12750. case '\\':
  12751. $this->position++;
  12752. $this->state = 'quote_escaped';
  12753. break;
  12754. default:
  12755. $this->state = 'quote_char';
  12756. break;
  12757. }
  12758. }
  12759. }
  12760. /**
  12761. * Parse a header value while within quotes
  12762. */
  12763. protected function quote_char()
  12764. {
  12765. $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
  12766. $this->value .= substr($this->data, $this->position, $len);
  12767. $this->position += $len;
  12768. $this->state = 'value';
  12769. }
  12770. /**
  12771. * Parse an escaped character within quotes
  12772. */
  12773. protected function quote_escaped()
  12774. {
  12775. $this->value .= $this->data[$this->position];
  12776. $this->position++;
  12777. $this->state = 'quote';
  12778. }
  12779. /**
  12780. * Parse the body
  12781. */
  12782. protected function body()
  12783. {
  12784. $this->body = substr($this->data, $this->position);
  12785. if (!empty($this->headers['transfer-encoding']))
  12786. {
  12787. unset($this->headers['transfer-encoding']);
  12788. $this->state = 'chunked';
  12789. }
  12790. else
  12791. {
  12792. $this->state = 'emit';
  12793. }
  12794. }
  12795. /**
  12796. * Parsed a "Transfer-Encoding: chunked" body
  12797. */
  12798. protected function chunked()
  12799. {
  12800. if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
  12801. {
  12802. $this->state = 'emit';
  12803. return;
  12804. }
  12805. $decoded = '';
  12806. $encoded = $this->body;
  12807. while (true)
  12808. {
  12809. $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
  12810. if (!$is_chunked)
  12811. {
  12812. // Looks like it's not chunked after all
  12813. $this->state = 'emit';
  12814. return;
  12815. }
  12816. $length = hexdec(trim($matches[1]));
  12817. if ($length === 0)
  12818. {
  12819. // Ignore trailer headers
  12820. $this->state = 'emit';
  12821. $this->body = $decoded;
  12822. return;
  12823. }
  12824. $chunk_length = strlen($matches[0]);
  12825. $decoded .= $part = substr($encoded, $chunk_length, $length);
  12826. $encoded = substr($encoded, $chunk_length + $length + 2);
  12827. if (trim($encoded) === '0' || empty($encoded))
  12828. {
  12829. $this->state = 'emit';
  12830. $this->body = $decoded;
  12831. return;
  12832. }
  12833. }
  12834. }
  12835. }
  12836. /**
  12837. * SimplePie class.
  12838. *
  12839. * Class for backward compatibility.
  12840. *
  12841. * @deprecated Use {@see SimplePie} directly
  12842. * @package SimplePie
  12843. * @subpackage API
  12844. */
  12845. class SimplePie_Core extends SimplePie
  12846. {
  12847. }
  12848. /**
  12849. * Handles `<media:restriction>` as defined in Media RSS
  12850. *
  12851. * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
  12852. *
  12853. * This class can be overloaded with {@see SimplePie::set_restriction_class()}
  12854. *
  12855. * @package SimplePie
  12856. * @subpackage API
  12857. */
  12858. class SimplePie_Restriction
  12859. {
  12860. /**
  12861. * Relationship ('allow'/'deny')
  12862. *
  12863. * @var string
  12864. * @see get_relationship()
  12865. */
  12866. var $relationship;
  12867. /**
  12868. * Type of restriction
  12869. *
  12870. * @var string
  12871. * @see get_type()
  12872. */
  12873. var $type;
  12874. /**
  12875. * Restricted values
  12876. *
  12877. * @var string
  12878. * @see get_value()
  12879. */
  12880. var $value;
  12881. /**
  12882. * Constructor, used to input the data
  12883. *
  12884. * For documentation on all the parameters, see the corresponding
  12885. * properties and their accessors
  12886. */
  12887. public function __construct($relationship = null, $type = null, $value = null)
  12888. {
  12889. $this->relationship = $relationship;
  12890. $this->type = $type;
  12891. $this->value = $value;
  12892. }
  12893. /**
  12894. * String-ified version
  12895. *
  12896. * @return string
  12897. */
  12898. public function __toString()
  12899. {
  12900. // There is no $this->data here
  12901. return md5(serialize($this));
  12902. }
  12903. /**
  12904. * Get the relationship
  12905. *
  12906. * @return string|null Either 'allow' or 'deny'
  12907. */
  12908. public function get_relationship()
  12909. {
  12910. if ($this->relationship !== null)
  12911. {
  12912. return $this->relationship;
  12913. }
  12914. else
  12915. {
  12916. return null;
  12917. }
  12918. }
  12919. /**
  12920. * Get the type
  12921. *
  12922. * @return string|null
  12923. */
  12924. public function get_type()
  12925. {
  12926. if ($this->type !== null)
  12927. {
  12928. return $this->type;
  12929. }
  12930. else
  12931. {
  12932. return null;
  12933. }
  12934. }
  12935. /**
  12936. * Get the list of restricted things
  12937. *
  12938. * @return string|null
  12939. */
  12940. public function get_value()
  12941. {
  12942. if ($this->value !== null)
  12943. {
  12944. return $this->value;
  12945. }
  12946. else
  12947. {
  12948. return null;
  12949. }
  12950. }
  12951. }
  12952. /**
  12953. * Handles `<atom:source>`
  12954. *
  12955. * Used by {@see SimplePie_Item::get_source()}
  12956. *
  12957. * This class can be overloaded with {@see SimplePie::set_source_class()}
  12958. *
  12959. * @package SimplePie
  12960. * @subpackage API
  12961. */
  12962. class SimplePie_Source
  12963. {
  12964. var $item;
  12965. var $data = array();
  12966. protected $registry;
  12967. public function __construct($item, $data)
  12968. {
  12969. $this->item = $item;
  12970. $this->data = $data;
  12971. }
  12972. public function set_registry(SimplePie_Registry $registry)
  12973. {
  12974. $this->registry = $registry;
  12975. }
  12976. public function __toString()
  12977. {
  12978. return md5(serialize($this->data));
  12979. }
  12980. public function get_source_tags($namespace, $tag)
  12981. {
  12982. if (isset($this->data['child'][$namespace][$tag]))
  12983. {
  12984. return $this->data['child'][$namespace][$tag];
  12985. }
  12986. else
  12987. {
  12988. return null;
  12989. }
  12990. }
  12991. public function get_base($element = array())
  12992. {
  12993. return $this->item->get_base($element);
  12994. }
  12995. public function sanitize($data, $type, $base = '')
  12996. {
  12997. return $this->item->sanitize($data, $type, $base);
  12998. }
  12999. public function get_item()
  13000. {
  13001. return $this->item;
  13002. }
  13003. public function get_title()
  13004. {
  13005. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  13006. {
  13007. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13008. }
  13009. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  13010. {
  13011. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13012. }
  13013. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  13014. {
  13015. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13016. }
  13017. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  13018. {
  13019. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13020. }
  13021. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  13022. {
  13023. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13024. }
  13025. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  13026. {
  13027. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13028. }
  13029. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  13030. {
  13031. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13032. }
  13033. else
  13034. {
  13035. return null;
  13036. }
  13037. }
  13038. public function get_category($key = 0)
  13039. {
  13040. $categories = $this->get_categories();
  13041. if (isset($categories[$key]))
  13042. {
  13043. return $categories[$key];
  13044. }
  13045. else
  13046. {
  13047. return null;
  13048. }
  13049. }
  13050. public function get_categories()
  13051. {
  13052. $categories = array();
  13053. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  13054. {
  13055. $term = null;
  13056. $scheme = null;
  13057. $label = null;
  13058. if (isset($category['attribs']['']['term']))
  13059. {
  13060. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  13061. }
  13062. if (isset($category['attribs']['']['scheme']))
  13063. {
  13064. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  13065. }
  13066. if (isset($category['attribs']['']['label']))
  13067. {
  13068. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  13069. }
  13070. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  13071. }
  13072. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  13073. {
  13074. // This is really the label, but keep this as the term also for BC.
  13075. // Label will also work on retrieving because that falls back to term.
  13076. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13077. if (isset($category['attribs']['']['domain']))
  13078. {
  13079. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  13080. }
  13081. else
  13082. {
  13083. $scheme = null;
  13084. }
  13085. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  13086. }
  13087. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  13088. {
  13089. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13090. }
  13091. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  13092. {
  13093. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13094. }
  13095. if (!empty($categories))
  13096. {
  13097. return array_unique($categories);
  13098. }
  13099. else
  13100. {
  13101. return null;
  13102. }
  13103. }
  13104. public function get_author($key = 0)
  13105. {
  13106. $authors = $this->get_authors();
  13107. if (isset($authors[$key]))
  13108. {
  13109. return $authors[$key];
  13110. }
  13111. else
  13112. {
  13113. return null;
  13114. }
  13115. }
  13116. public function get_authors()
  13117. {
  13118. $authors = array();
  13119. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  13120. {
  13121. $name = null;
  13122. $uri = null;
  13123. $email = null;
  13124. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  13125. {
  13126. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13127. }
  13128. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  13129. {
  13130. $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]));
  13131. }
  13132. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  13133. {
  13134. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13135. }
  13136. if ($name !== null || $email !== null || $uri !== null)
  13137. {
  13138. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  13139. }
  13140. }
  13141. if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  13142. {
  13143. $name = null;
  13144. $url = null;
  13145. $email = null;
  13146. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  13147. {
  13148. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13149. }
  13150. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  13151. {
  13152. $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]));
  13153. }
  13154. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  13155. {
  13156. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13157. }
  13158. if ($name !== null || $email !== null || $url !== null)
  13159. {
  13160. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  13161. }
  13162. }
  13163. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  13164. {
  13165. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13166. }
  13167. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  13168. {
  13169. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13170. }
  13171. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  13172. {
  13173. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13174. }
  13175. if (!empty($authors))
  13176. {
  13177. return array_unique($authors);
  13178. }
  13179. else
  13180. {
  13181. return null;
  13182. }
  13183. }
  13184. public function get_contributor($key = 0)
  13185. {
  13186. $contributors = $this->get_contributors();
  13187. if (isset($contributors[$key]))
  13188. {
  13189. return $contributors[$key];
  13190. }
  13191. else
  13192. {
  13193. return null;
  13194. }
  13195. }
  13196. public function get_contributors()
  13197. {
  13198. $contributors = array();
  13199. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  13200. {
  13201. $name = null;
  13202. $uri = null;
  13203. $email = null;
  13204. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  13205. {
  13206. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13207. }
  13208. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  13209. {
  13210. $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]));
  13211. }
  13212. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  13213. {
  13214. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13215. }
  13216. if ($name !== null || $email !== null || $uri !== null)
  13217. {
  13218. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  13219. }
  13220. }
  13221. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  13222. {
  13223. $name = null;
  13224. $url = null;
  13225. $email = null;
  13226. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  13227. {
  13228. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13229. }
  13230. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  13231. {
  13232. $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]));
  13233. }
  13234. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  13235. {
  13236. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13237. }
  13238. if ($name !== null || $email !== null || $url !== null)
  13239. {
  13240. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  13241. }
  13242. }
  13243. if (!empty($contributors))
  13244. {
  13245. return array_unique($contributors);
  13246. }
  13247. else
  13248. {
  13249. return null;
  13250. }
  13251. }
  13252. public function get_link($key = 0, $rel = 'alternate')
  13253. {
  13254. $links = $this->get_links($rel);
  13255. if (isset($links[$key]))
  13256. {
  13257. return $links[$key];
  13258. }
  13259. else
  13260. {
  13261. return null;
  13262. }
  13263. }
  13264. /**
  13265. * Added for parity between the parent-level and the item/entry-level.
  13266. */
  13267. public function get_permalink()
  13268. {
  13269. return $this->get_link(0);
  13270. }
  13271. public function get_links($rel = 'alternate')
  13272. {
  13273. if (!isset($this->data['links']))
  13274. {
  13275. $this->data['links'] = array();
  13276. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  13277. {
  13278. foreach ($links as $link)
  13279. {
  13280. if (isset($link['attribs']['']['href']))
  13281. {
  13282. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  13283. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  13284. }
  13285. }
  13286. }
  13287. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  13288. {
  13289. foreach ($links as $link)
  13290. {
  13291. if (isset($link['attribs']['']['href']))
  13292. {
  13293. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  13294. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  13295. }
  13296. }
  13297. }
  13298. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  13299. {
  13300. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  13301. }
  13302. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  13303. {
  13304. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  13305. }
  13306. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  13307. {
  13308. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  13309. }
  13310. $keys = array_keys($this->data['links']);
  13311. foreach ($keys as $key)
  13312. {
  13313. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  13314. {
  13315. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  13316. {
  13317. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  13318. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  13319. }
  13320. else
  13321. {
  13322. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  13323. }
  13324. }
  13325. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  13326. {
  13327. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  13328. }
  13329. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  13330. }
  13331. }
  13332. if (isset($this->data['links'][$rel]))
  13333. {
  13334. return $this->data['links'][$rel];
  13335. }
  13336. else
  13337. {
  13338. return null;
  13339. }
  13340. }
  13341. public function get_description()
  13342. {
  13343. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  13344. {
  13345. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13346. }
  13347. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  13348. {
  13349. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13350. }
  13351. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  13352. {
  13353. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13354. }
  13355. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  13356. {
  13357. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13358. }
  13359. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  13360. {
  13361. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13362. }
  13363. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  13364. {
  13365. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13366. }
  13367. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  13368. {
  13369. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13370. }
  13371. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  13372. {
  13373. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  13374. }
  13375. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  13376. {
  13377. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  13378. }
  13379. else
  13380. {
  13381. return null;
  13382. }
  13383. }
  13384. public function get_copyright()
  13385. {
  13386. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  13387. {
  13388. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13389. }
  13390. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  13391. {
  13392. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13393. }
  13394. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  13395. {
  13396. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13397. }
  13398. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  13399. {
  13400. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13401. }
  13402. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  13403. {
  13404. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13405. }
  13406. else
  13407. {
  13408. return null;
  13409. }
  13410. }
  13411. public function get_language()
  13412. {
  13413. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  13414. {
  13415. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13416. }
  13417. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  13418. {
  13419. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13420. }
  13421. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  13422. {
  13423. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13424. }
  13425. elseif (isset($this->data['xml_lang']))
  13426. {
  13427. return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  13428. }
  13429. else
  13430. {
  13431. return null;
  13432. }
  13433. }
  13434. public function get_latitude()
  13435. {
  13436. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  13437. {
  13438. return (float) $return[0]['data'];
  13439. }
  13440. elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
  13441. {
  13442. return (float) $match[1];
  13443. }
  13444. else
  13445. {
  13446. return null;
  13447. }
  13448. }
  13449. public function get_longitude()
  13450. {
  13451. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  13452. {
  13453. return (float) $return[0]['data'];
  13454. }
  13455. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  13456. {
  13457. return (float) $return[0]['data'];
  13458. }
  13459. elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
  13460. {
  13461. return (float) $match[2];
  13462. }
  13463. else
  13464. {
  13465. return null;
  13466. }
  13467. }
  13468. public function get_image_url()
  13469. {
  13470. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
  13471. {
  13472. return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
  13473. }
  13474. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  13475. {
  13476. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  13477. }
  13478. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  13479. {
  13480. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  13481. }
  13482. else
  13483. {
  13484. return null;
  13485. }
  13486. }
  13487. }
  13488. /**
  13489. * Miscellanous utilities
  13490. *
  13491. * @package SimplePie
  13492. */
  13493. class SimplePie_Misc
  13494. {
  13495. public static function time_hms($seconds)
  13496. {
  13497. $time = '';
  13498. $hours = floor($seconds / 3600);
  13499. $remainder = $seconds % 3600;
  13500. if ($hours > 0)
  13501. {
  13502. $time .= $hours.':';
  13503. }
  13504. $minutes = floor($remainder / 60);
  13505. $seconds = $remainder % 60;
  13506. if ($minutes < 10 && $hours > 0)
  13507. {
  13508. $minutes = '0' . $minutes;
  13509. }
  13510. if ($seconds < 10)
  13511. {
  13512. $seconds = '0' . $seconds;
  13513. }
  13514. $time .= $minutes.':';
  13515. $time .= $seconds;
  13516. return $time;
  13517. }
  13518. public static function absolutize_url($relative, $base)
  13519. {
  13520. $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
  13521. return $iri->get_uri();
  13522. }
  13523. /**
  13524. * Get a HTML/XML element from a HTML string
  13525. *
  13526. * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
  13527. * @param string $realname Element name (including namespace prefix if applicable)
  13528. * @param string $string HTML document
  13529. * @return array
  13530. */
  13531. public static function get_element($realname, $string)
  13532. {
  13533. $return = array();
  13534. $name = preg_quote($realname, '/');
  13535. if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
  13536. {
  13537. for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
  13538. {
  13539. $return[$i]['tag'] = $realname;
  13540. $return[$i]['full'] = $matches[$i][0][0];
  13541. $return[$i]['offset'] = $matches[$i][0][1];
  13542. if (strlen($matches[$i][3][0]) <= 2)
  13543. {
  13544. $return[$i]['self_closing'] = true;
  13545. }
  13546. else
  13547. {
  13548. $return[$i]['self_closing'] = false;
  13549. $return[$i]['content'] = $matches[$i][4][0];
  13550. }
  13551. $return[$i]['attribs'] = array();
  13552. 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))
  13553. {
  13554. for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
  13555. {
  13556. if (count($attribs[$j]) === 2)
  13557. {
  13558. $attribs[$j][2] = $attribs[$j][1];
  13559. }
  13560. $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
  13561. }
  13562. }
  13563. }
  13564. }
  13565. return $return;
  13566. }
  13567. public static function element_implode($element)
  13568. {
  13569. $full = "<$element[tag]";
  13570. foreach ($element['attribs'] as $key => $value)
  13571. {
  13572. $key = strtolower($key);
  13573. $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
  13574. }
  13575. if ($element['self_closing'])
  13576. {
  13577. $full .= ' />';
  13578. }
  13579. else
  13580. {
  13581. $full .= ">$element[content]</$element[tag]>";
  13582. }
  13583. return $full;
  13584. }
  13585. public static function error($message, $level, $file, $line)
  13586. {
  13587. if ((ini_get('error_reporting') & $level) > 0)
  13588. {
  13589. switch ($level)
  13590. {
  13591. case E_USER_ERROR:
  13592. $note = 'PHP Error';
  13593. break;
  13594. case E_USER_WARNING:
  13595. $note = 'PHP Warning';
  13596. break;
  13597. case E_USER_NOTICE:
  13598. $note = 'PHP Notice';
  13599. break;
  13600. default:
  13601. $note = 'Unknown Error';
  13602. break;
  13603. }
  13604. $log_error = true;
  13605. if (!function_exists('error_log'))
  13606. {
  13607. $log_error = false;
  13608. }
  13609. $log_file = @ini_get('error_log');
  13610. if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
  13611. {
  13612. $log_error = false;
  13613. }
  13614. if ($log_error)
  13615. {
  13616. @error_log("$note: $message in $file on line $line", 0);
  13617. }
  13618. }
  13619. return $message;
  13620. }
  13621. public static function fix_protocol($url, $http = 1)
  13622. {
  13623. $url = SimplePie_Misc::normalize_url($url);
  13624. $parsed = SimplePie_Misc::parse_url($url);
  13625. if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
  13626. {
  13627. return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
  13628. }
  13629. if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
  13630. {
  13631. return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
  13632. }
  13633. if ($http === 2 && $parsed['scheme'] !== '')
  13634. {
  13635. return "feed:$url";
  13636. }
  13637. elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
  13638. {
  13639. return substr_replace($url, 'podcast', 0, 4);
  13640. }
  13641. elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
  13642. {
  13643. return substr_replace($url, 'itpc', 0, 4);
  13644. }
  13645. else
  13646. {
  13647. return $url;
  13648. }
  13649. }
  13650. public static function parse_url($url)
  13651. {
  13652. $iri = new SimplePie_IRI($url);
  13653. return array(
  13654. 'scheme' => (string) $iri->scheme,
  13655. 'authority' => (string) $iri->authority,
  13656. 'path' => (string) $iri->path,
  13657. 'query' => (string) $iri->query,
  13658. 'fragment' => (string) $iri->fragment
  13659. );
  13660. }
  13661. public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
  13662. {
  13663. $iri = new SimplePie_IRI('');
  13664. $iri->scheme = $scheme;
  13665. $iri->authority = $authority;
  13666. $iri->path = $path;
  13667. $iri->query = $query;
  13668. $iri->fragment = $fragment;
  13669. return $iri->get_uri();
  13670. }
  13671. public static function normalize_url($url)
  13672. {
  13673. $iri = new SimplePie_IRI($url);
  13674. return $iri->get_uri();
  13675. }
  13676. public static function percent_encoding_normalization($match)
  13677. {
  13678. $integer = hexdec($match[1]);
  13679. if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
  13680. {
  13681. return chr($integer);
  13682. }
  13683. else
  13684. {
  13685. return strtoupper($match[0]);
  13686. }
  13687. }
  13688. /**
  13689. * Converts a Windows-1252 encoded string to a UTF-8 encoded string
  13690. *
  13691. * @static
  13692. * @param string $string Windows-1252 encoded string
  13693. * @return string UTF-8 encoded string
  13694. */
  13695. public static function windows_1252_to_utf8($string)
  13696. {
  13697. static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
  13698. return strtr($string, $convert_table);
  13699. }
  13700. /**
  13701. * Change a string from one encoding to another
  13702. *
  13703. * @param string $data Raw data in $input encoding
  13704. * @param string $input Encoding of $data
  13705. * @param string $output Encoding you want
  13706. * @return string|boolean False if we can't convert it
  13707. */
  13708. public static function change_encoding($data, $input, $output)
  13709. {
  13710. $input = SimplePie_Misc::encoding($input);
  13711. $output = SimplePie_Misc::encoding($output);
  13712. // We fail to fail on non US-ASCII bytes
  13713. if ($input === 'US-ASCII')
  13714. {
  13715. static $non_ascii_octects = '';
  13716. if (!$non_ascii_octects)
  13717. {
  13718. for ($i = 0x80; $i <= 0xFF; $i++)
  13719. {
  13720. $non_ascii_octects .= chr($i);
  13721. }
  13722. }
  13723. $data = substr($data, 0, strcspn($data, $non_ascii_octects));
  13724. }
  13725. // This is first, as behaviour of this is completely predictable
  13726. if ($input === 'windows-1252' && $output === 'UTF-8')
  13727. {
  13728. return SimplePie_Misc::windows_1252_to_utf8($data);
  13729. }
  13730. // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
  13731. elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
  13732. {
  13733. return $return;
  13734. }
  13735. // This is last, as behaviour of this varies with OS userland and PHP version
  13736. elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
  13737. {
  13738. return $return;
  13739. }
  13740. // If we can't do anything, just fail
  13741. else
  13742. {
  13743. return false;
  13744. }
  13745. }
  13746. protected static function change_encoding_mbstring($data, $input, $output)
  13747. {
  13748. if ($input === 'windows-949')
  13749. {
  13750. $input = 'EUC-KR';
  13751. }
  13752. if ($output === 'windows-949')
  13753. {
  13754. $output = 'EUC-KR';
  13755. }
  13756. if ($input === 'Windows-31J')
  13757. {
  13758. $input = 'SJIS';
  13759. }
  13760. if ($output === 'Windows-31J')
  13761. {
  13762. $output = 'SJIS';
  13763. }
  13764. // Check that the encoding is supported
  13765. if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
  13766. {
  13767. return false;
  13768. }
  13769. if (!in_array($input, mb_list_encodings()))
  13770. {
  13771. return false;
  13772. }
  13773. // Let's do some conversion
  13774. if ($return = @mb_convert_encoding($data, $output, $input))
  13775. {
  13776. return $return;
  13777. }
  13778. return false;
  13779. }
  13780. protected static function change_encoding_iconv($data, $input, $output)
  13781. {
  13782. return @iconv($input, $output, $data);
  13783. }
  13784. /**
  13785. * Normalize an encoding name
  13786. *
  13787. * This is automatically generated by create.php
  13788. *
  13789. * To generate it, run `php create.php` on the command line, and copy the
  13790. * output to replace this function.
  13791. *
  13792. * @param string $charset Character set to standardise
  13793. * @return string Standardised name
  13794. */
  13795. public static function encoding($charset)
  13796. {
  13797. // Normalization from UTS #22
  13798. switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
  13799. {
  13800. case 'adobestandardencoding':
  13801. case 'csadobestandardencoding':
  13802. return 'Adobe-Standard-Encoding';
  13803. case 'adobesymbolencoding':
  13804. case 'cshppsmath':
  13805. return 'Adobe-Symbol-Encoding';
  13806. case 'ami1251':
  13807. case 'amiga1251':
  13808. return 'Amiga-1251';
  13809. case 'ansix31101983':
  13810. case 'csat5001983':
  13811. case 'csiso99naplps':
  13812. case 'isoir99':
  13813. case 'naplps':
  13814. return 'ANSI_X3.110-1983';
  13815. case 'arabic7':
  13816. case 'asmo449':
  13817. case 'csiso89asmo449':
  13818. case 'iso9036':
  13819. case 'isoir89':
  13820. return 'ASMO_449';
  13821. case 'big5':
  13822. case 'csbig5':
  13823. return 'Big5';
  13824. case 'big5hkscs':
  13825. return 'Big5-HKSCS';
  13826. case 'bocu1':
  13827. case 'csbocu1':
  13828. return 'BOCU-1';
  13829. case 'brf':
  13830. case 'csbrf':
  13831. return 'BRF';
  13832. case 'bs4730':
  13833. case 'csiso4unitedkingdom':
  13834. case 'gb':
  13835. case 'iso646gb':
  13836. case 'isoir4':
  13837. case 'uk':
  13838. return 'BS_4730';
  13839. case 'bsviewdata':
  13840. case 'csiso47bsviewdata':
  13841. case 'isoir47':
  13842. return 'BS_viewdata';
  13843. case 'cesu8':
  13844. case 'cscesu8':
  13845. return 'CESU-8';
  13846. case 'ca':
  13847. case 'csa71':
  13848. case 'csaz243419851':
  13849. case 'csiso121canadian1':
  13850. case 'iso646ca':
  13851. case 'isoir121':
  13852. return 'CSA_Z243.4-1985-1';
  13853. case 'csa72':
  13854. case 'csaz243419852':
  13855. case 'csiso122canadian2':
  13856. case 'iso646ca2':
  13857. case 'isoir122':
  13858. return 'CSA_Z243.4-1985-2';
  13859. case 'csaz24341985gr':
  13860. case 'csiso123csaz24341985gr':
  13861. case 'isoir123':
  13862. return 'CSA_Z243.4-1985-gr';
  13863. case 'csiso139csn369103':
  13864. case 'csn369103':
  13865. case 'isoir139':
  13866. return 'CSN_369103';
  13867. case 'csdecmcs':
  13868. case 'dec':
  13869. case 'decmcs':
  13870. return 'DEC-MCS';
  13871. case 'csiso21german':
  13872. case 'de':
  13873. case 'din66003':
  13874. case 'iso646de':
  13875. case 'isoir21':
  13876. return 'DIN_66003';
  13877. case 'csdkus':
  13878. case 'dkus':
  13879. return 'dk-us';
  13880. case 'csiso646danish':
  13881. case 'dk':
  13882. case 'ds2089':
  13883. case 'iso646dk':
  13884. return 'DS_2089';
  13885. case 'csibmebcdicatde':
  13886. case 'ebcdicatde':
  13887. return 'EBCDIC-AT-DE';
  13888. case 'csebcdicatdea':
  13889. case 'ebcdicatdea':
  13890. return 'EBCDIC-AT-DE-A';
  13891. case 'csebcdiccafr':
  13892. case 'ebcdiccafr':
  13893. return 'EBCDIC-CA-FR';
  13894. case 'csebcdicdkno':
  13895. case 'ebcdicdkno':
  13896. return 'EBCDIC-DK-NO';
  13897. case 'csebcdicdknoa':
  13898. case 'ebcdicdknoa':
  13899. return 'EBCDIC-DK-NO-A';
  13900. case 'csebcdices':
  13901. case 'ebcdices':
  13902. return 'EBCDIC-ES';
  13903. case 'csebcdicesa':
  13904. case 'ebcdicesa':
  13905. return 'EBCDIC-ES-A';
  13906. case 'csebcdicess':
  13907. case 'ebcdicess':
  13908. return 'EBCDIC-ES-S';
  13909. case 'csebcdicfise':
  13910. case 'ebcdicfise':
  13911. return 'EBCDIC-FI-SE';
  13912. case 'csebcdicfisea':
  13913. case 'ebcdicfisea':
  13914. return 'EBCDIC-FI-SE-A';
  13915. case 'csebcdicfr':
  13916. case 'ebcdicfr':
  13917. return 'EBCDIC-FR';
  13918. case 'csebcdicit':
  13919. case 'ebcdicit':
  13920. return 'EBCDIC-IT';
  13921. case 'csebcdicpt':
  13922. case 'ebcdicpt':
  13923. return 'EBCDIC-PT';
  13924. case 'csebcdicuk':
  13925. case 'ebcdicuk':
  13926. return 'EBCDIC-UK';
  13927. case 'csebcdicus':
  13928. case 'ebcdicus':
  13929. return 'EBCDIC-US';
  13930. case 'csiso111ecmacyrillic':
  13931. case 'ecmacyrillic':
  13932. case 'isoir111':
  13933. case 'koi8e':
  13934. return 'ECMA-cyrillic';
  13935. case 'csiso17spanish':
  13936. case 'es':
  13937. case 'iso646es':
  13938. case 'isoir17':
  13939. return 'ES';
  13940. case 'csiso85spanish2':
  13941. case 'es2':
  13942. case 'iso646es2':
  13943. case 'isoir85':
  13944. return 'ES2';
  13945. case 'cseucpkdfmtjapanese':
  13946. case 'eucjp':
  13947. case 'extendedunixcodepackedformatforjapanese':
  13948. return 'EUC-JP';
  13949. case 'cseucfixwidjapanese':
  13950. case 'extendedunixcodefixedwidthforjapanese':
  13951. return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
  13952. case 'gb18030':
  13953. return 'GB18030';
  13954. case 'chinese':
  13955. case 'cp936':
  13956. case 'csgb2312':
  13957. case 'csiso58gb231280':
  13958. case 'gb2312':
  13959. case 'gb231280':
  13960. case 'gbk':
  13961. case 'isoir58':
  13962. case 'ms936':
  13963. case 'windows936':
  13964. return 'GBK';
  13965. case 'cn':
  13966. case 'csiso57gb1988':
  13967. case 'gb198880':
  13968. case 'iso646cn':
  13969. case 'isoir57':
  13970. return 'GB_1988-80';
  13971. case 'csiso153gost1976874':
  13972. case 'gost1976874':
  13973. case 'isoir153':
  13974. case 'stsev35888':
  13975. return 'GOST_19768-74';
  13976. case 'csiso150':
  13977. case 'csiso150greekccitt':
  13978. case 'greekccitt':
  13979. case 'isoir150':
  13980. return 'greek-ccitt';
  13981. case 'csiso88greek7':
  13982. case 'greek7':
  13983. case 'isoir88':
  13984. return 'greek7';
  13985. case 'csiso18greek7old':
  13986. case 'greek7old':
  13987. case 'isoir18':
  13988. return 'greek7-old';
  13989. case 'cshpdesktop':
  13990. case 'hpdesktop':
  13991. return 'HP-DeskTop';
  13992. case 'cshplegal':
  13993. case 'hplegal':
  13994. return 'HP-Legal';
  13995. case 'cshpmath8':
  13996. case 'hpmath8':
  13997. return 'HP-Math8';
  13998. case 'cshppifont':
  13999. case 'hppifont':
  14000. return 'HP-Pi-font';
  14001. case 'cshproman8':
  14002. case 'hproman8':
  14003. case 'r8':
  14004. case 'roman8':
  14005. return 'hp-roman8';
  14006. case 'hzgb2312':
  14007. return 'HZ-GB-2312';
  14008. case 'csibmsymbols':
  14009. case 'ibmsymbols':
  14010. return 'IBM-Symbols';
  14011. case 'csibmthai':
  14012. case 'ibmthai':
  14013. return 'IBM-Thai';
  14014. case 'cp37':
  14015. case 'csibm37':
  14016. case 'ebcdiccpca':
  14017. case 'ebcdiccpnl':
  14018. case 'ebcdiccpus':
  14019. case 'ebcdiccpwt':
  14020. case 'ibm37':
  14021. return 'IBM037';
  14022. case 'cp38':
  14023. case 'csibm38':
  14024. case 'ebcdicint':
  14025. case 'ibm38':
  14026. return 'IBM038';
  14027. case 'cp273':
  14028. case 'csibm273':
  14029. case 'ibm273':
  14030. return 'IBM273';
  14031. case 'cp274':
  14032. case 'csibm274':
  14033. case 'ebcdicbe':
  14034. case 'ibm274':
  14035. return 'IBM274';
  14036. case 'cp275':
  14037. case 'csibm275':
  14038. case 'ebcdicbr':
  14039. case 'ibm275':
  14040. return 'IBM275';
  14041. case 'csibm277':
  14042. case 'ebcdiccpdk':
  14043. case 'ebcdiccpno':
  14044. case 'ibm277':
  14045. return 'IBM277';
  14046. case 'cp278':
  14047. case 'csibm278':
  14048. case 'ebcdiccpfi':
  14049. case 'ebcdiccpse':
  14050. case 'ibm278':
  14051. return 'IBM278';
  14052. case 'cp280':
  14053. case 'csibm280':
  14054. case 'ebcdiccpit':
  14055. case 'ibm280':
  14056. return 'IBM280';
  14057. case 'cp281':
  14058. case 'csibm281':
  14059. case 'ebcdicjpe':
  14060. case 'ibm281':
  14061. return 'IBM281';
  14062. case 'cp284':
  14063. case 'csibm284':
  14064. case 'ebcdiccpes':
  14065. case 'ibm284':
  14066. return 'IBM284';
  14067. case 'cp285':
  14068. case 'csibm285':
  14069. case 'ebcdiccpgb':
  14070. case 'ibm285':
  14071. return 'IBM285';
  14072. case 'cp290':
  14073. case 'csibm290':
  14074. case 'ebcdicjpkana':
  14075. case 'ibm290':
  14076. return 'IBM290';
  14077. case 'cp297':
  14078. case 'csibm297':
  14079. case 'ebcdiccpfr':
  14080. case 'ibm297':
  14081. return 'IBM297';
  14082. case 'cp420':
  14083. case 'csibm420':
  14084. case 'ebcdiccpar1':
  14085. case 'ibm420':
  14086. return 'IBM420';
  14087. case 'cp423':
  14088. case 'csibm423':
  14089. case 'ebcdiccpgr':
  14090. case 'ibm423':
  14091. return 'IBM423';
  14092. case 'cp424':
  14093. case 'csibm424':
  14094. case 'ebcdiccphe':
  14095. case 'ibm424':
  14096. return 'IBM424';
  14097. case '437':
  14098. case 'cp437':
  14099. case 'cspc8codepage437':
  14100. case 'ibm437':
  14101. return 'IBM437';
  14102. case 'cp500':
  14103. case 'csibm500':
  14104. case 'ebcdiccpbe':
  14105. case 'ebcdiccpch':
  14106. case 'ibm500':
  14107. return 'IBM500';
  14108. case 'cp775':
  14109. case 'cspc775baltic':
  14110. case 'ibm775':
  14111. return 'IBM775';
  14112. case '850':
  14113. case 'cp850':
  14114. case 'cspc850multilingual':
  14115. case 'ibm850':
  14116. return 'IBM850';
  14117. case '851':
  14118. case 'cp851':
  14119. case 'csibm851':
  14120. case 'ibm851':
  14121. return 'IBM851';
  14122. case '852':
  14123. case 'cp852':
  14124. case 'cspcp852':
  14125. case 'ibm852':
  14126. return 'IBM852';
  14127. case '855':
  14128. case 'cp855':
  14129. case 'csibm855':
  14130. case 'ibm855':
  14131. return 'IBM855';
  14132. case '857':
  14133. case 'cp857':
  14134. case 'csibm857':
  14135. case 'ibm857':
  14136. return 'IBM857';
  14137. case 'ccsid858':
  14138. case 'cp858':
  14139. case 'ibm858':
  14140. case 'pcmultilingual850euro':
  14141. return 'IBM00858';
  14142. case '860':
  14143. case 'cp860':
  14144. case 'csibm860':
  14145. case 'ibm860':
  14146. return 'IBM860';
  14147. case '861':
  14148. case 'cp861':
  14149. case 'cpis':
  14150. case 'csibm861':
  14151. case 'ibm861':
  14152. return 'IBM861';
  14153. case '862':
  14154. case 'cp862':
  14155. case 'cspc862latinhebrew':
  14156. case 'ibm862':
  14157. return 'IBM862';
  14158. case '863':
  14159. case 'cp863':
  14160. case 'csibm863':
  14161. case 'ibm863':
  14162. return 'IBM863';
  14163. case 'cp864':
  14164. case 'csibm864':
  14165. case 'ibm864':
  14166. return 'IBM864';
  14167. case '865':
  14168. case 'cp865':
  14169. case 'csibm865':
  14170. case 'ibm865':
  14171. return 'IBM865';
  14172. case '866':
  14173. case 'cp866':
  14174. case 'csibm866':
  14175. case 'ibm866':
  14176. return 'IBM866';
  14177. case 'cp868':
  14178. case 'cpar':
  14179. case 'csibm868':
  14180. case 'ibm868':
  14181. return 'IBM868';
  14182. case '869':
  14183. case 'cp869':
  14184. case 'cpgr':
  14185. case 'csibm869':
  14186. case 'ibm869':
  14187. return 'IBM869';
  14188. case 'cp870':
  14189. case 'csibm870':
  14190. case 'ebcdiccproece':
  14191. case 'ebcdiccpyu':
  14192. case 'ibm870':
  14193. return 'IBM870';
  14194. case 'cp871':
  14195. case 'csibm871':
  14196. case 'ebcdiccpis':
  14197. case 'ibm871':
  14198. return 'IBM871';
  14199. case 'cp880':
  14200. case 'csibm880':
  14201. case 'ebcdiccyrillic':
  14202. case 'ibm880':
  14203. return 'IBM880';
  14204. case 'cp891':
  14205. case 'csibm891':
  14206. case 'ibm891':
  14207. return 'IBM891';
  14208. case 'cp903':
  14209. case 'csibm903':
  14210. case 'ibm903':
  14211. return 'IBM903';
  14212. case '904':
  14213. case 'cp904':
  14214. case 'csibbm904':
  14215. case 'ibm904':
  14216. return 'IBM904';
  14217. case 'cp905':
  14218. case 'csibm905':
  14219. case 'ebcdiccptr':
  14220. case 'ibm905':
  14221. return 'IBM905';
  14222. case 'cp918':
  14223. case 'csibm918':
  14224. case 'ebcdiccpar2':
  14225. case 'ibm918':
  14226. return 'IBM918';
  14227. case 'ccsid924':
  14228. case 'cp924':
  14229. case 'ebcdiclatin9euro':
  14230. case 'ibm924':
  14231. return 'IBM00924';
  14232. case 'cp1026':
  14233. case 'csibm1026':
  14234. case 'ibm1026':
  14235. return 'IBM1026';
  14236. case 'ibm1047':
  14237. return 'IBM1047';
  14238. case 'ccsid1140':
  14239. case 'cp1140':
  14240. case 'ebcdicus37euro':
  14241. case 'ibm1140':
  14242. return 'IBM01140';
  14243. case 'ccsid1141':
  14244. case 'cp1141':
  14245. case 'ebcdicde273euro':
  14246. case 'ibm1141':
  14247. return 'IBM01141';
  14248. case 'ccsid1142':
  14249. case 'cp1142':
  14250. case 'ebcdicdk277euro':
  14251. case 'ebcdicno277euro':
  14252. case 'ibm1142':
  14253. return 'IBM01142';
  14254. case 'ccsid1143':
  14255. case 'cp1143':
  14256. case 'ebcdicfi278euro':
  14257. case 'ebcdicse278euro':
  14258. case 'ibm1143':
  14259. return 'IBM01143';
  14260. case 'ccsid1144':
  14261. case 'cp1144':
  14262. case 'ebcdicit280euro':
  14263. case 'ibm1144':
  14264. return 'IBM01144';
  14265. case 'ccsid1145':
  14266. case 'cp1145':
  14267. case 'ebcdices284euro':
  14268. case 'ibm1145':
  14269. return 'IBM01145';
  14270. case 'ccsid1146':
  14271. case 'cp1146':
  14272. case 'ebcdicgb285euro':
  14273. case 'ibm1146':
  14274. return 'IBM01146';
  14275. case 'ccsid1147':
  14276. case 'cp1147':
  14277. case 'ebcdicfr297euro':
  14278. case 'ibm1147':
  14279. return 'IBM01147';
  14280. case 'ccsid1148':
  14281. case 'cp1148':
  14282. case 'ebcdicinternational500euro':
  14283. case 'ibm1148':
  14284. return 'IBM01148';
  14285. case 'ccsid1149':
  14286. case 'cp1149':
  14287. case 'ebcdicis871euro':
  14288. case 'ibm1149':
  14289. return 'IBM01149';
  14290. case 'csiso143iecp271':
  14291. case 'iecp271':
  14292. case 'isoir143':
  14293. return 'IEC_P27-1';
  14294. case 'csiso49inis':
  14295. case 'inis':
  14296. case 'isoir49':
  14297. return 'INIS';
  14298. case 'csiso50inis8':
  14299. case 'inis8':
  14300. case 'isoir50':
  14301. return 'INIS-8';
  14302. case 'csiso51iniscyrillic':
  14303. case 'iniscyrillic':
  14304. case 'isoir51':
  14305. return 'INIS-cyrillic';
  14306. case 'csinvariant':
  14307. case 'invariant':
  14308. return 'INVARIANT';
  14309. case 'iso2022cn':
  14310. return 'ISO-2022-CN';
  14311. case 'iso2022cnext':
  14312. return 'ISO-2022-CN-EXT';
  14313. case 'csiso2022jp':
  14314. case 'iso2022jp':
  14315. return 'ISO-2022-JP';
  14316. case 'csiso2022jp2':
  14317. case 'iso2022jp2':
  14318. return 'ISO-2022-JP-2';
  14319. case 'csiso2022kr':
  14320. case 'iso2022kr':
  14321. return 'ISO-2022-KR';
  14322. case 'cswindows30latin1':
  14323. case 'iso88591windows30latin1':
  14324. return 'ISO-8859-1-Windows-3.0-Latin-1';
  14325. case 'cswindows31latin1':
  14326. case 'iso88591windows31latin1':
  14327. return 'ISO-8859-1-Windows-3.1-Latin-1';
  14328. case 'csisolatin2':
  14329. case 'iso88592':
  14330. case 'iso885921987':
  14331. case 'isoir101':
  14332. case 'l2':
  14333. case 'latin2':
  14334. return 'ISO-8859-2';
  14335. case 'cswindows31latin2':
  14336. case 'iso88592windowslatin2':
  14337. return 'ISO-8859-2-Windows-Latin-2';
  14338. case 'csisolatin3':
  14339. case 'iso88593':
  14340. case 'iso885931988':
  14341. case 'isoir109':
  14342. case 'l3':
  14343. case 'latin3':
  14344. return 'ISO-8859-3';
  14345. case 'csisolatin4':
  14346. case 'iso88594':
  14347. case 'iso885941988':
  14348. case 'isoir110':
  14349. case 'l4':
  14350. case 'latin4':
  14351. return 'ISO-8859-4';
  14352. case 'csisolatincyrillic':
  14353. case 'cyrillic':
  14354. case 'iso88595':
  14355. case 'iso885951988':
  14356. case 'isoir144':
  14357. return 'ISO-8859-5';
  14358. case 'arabic':
  14359. case 'asmo708':
  14360. case 'csisolatinarabic':
  14361. case 'ecma114':
  14362. case 'iso88596':
  14363. case 'iso885961987':
  14364. case 'isoir127':
  14365. return 'ISO-8859-6';
  14366. case 'csiso88596e':
  14367. case 'iso88596e':
  14368. return 'ISO-8859-6-E';
  14369. case 'csiso88596i':
  14370. case 'iso88596i':
  14371. return 'ISO-8859-6-I';
  14372. case 'csisolatingreek':
  14373. case 'ecma118':
  14374. case 'elot928':
  14375. case 'greek':
  14376. case 'greek8':
  14377. case 'iso88597':
  14378. case 'iso885971987':
  14379. case 'isoir126':
  14380. return 'ISO-8859-7';
  14381. case 'csisolatinhebrew':
  14382. case 'hebrew':
  14383. case 'iso88598':
  14384. case 'iso885981988':
  14385. case 'isoir138':
  14386. return 'ISO-8859-8';
  14387. case 'csiso88598e':
  14388. case 'iso88598e':
  14389. return 'ISO-8859-8-E';
  14390. case 'csiso88598i':
  14391. case 'iso88598i':
  14392. return 'ISO-8859-8-I';
  14393. case 'cswindows31latin5':
  14394. case 'iso88599windowslatin5':
  14395. return 'ISO-8859-9-Windows-Latin-5';
  14396. case 'csisolatin6':
  14397. case 'iso885910':
  14398. case 'iso8859101992':
  14399. case 'isoir157':
  14400. case 'l6':
  14401. case 'latin6':
  14402. return 'ISO-8859-10';
  14403. case 'iso885913':
  14404. return 'ISO-8859-13';
  14405. case 'iso885914':
  14406. case 'iso8859141998':
  14407. case 'isoceltic':
  14408. case 'isoir199':
  14409. case 'l8':
  14410. case 'latin8':
  14411. return 'ISO-8859-14';
  14412. case 'iso885915':
  14413. case 'latin9':
  14414. return 'ISO-8859-15';
  14415. case 'iso885916':
  14416. case 'iso8859162001':
  14417. case 'isoir226':
  14418. case 'l10':
  14419. case 'latin10':
  14420. return 'ISO-8859-16';
  14421. case 'iso10646j1':
  14422. return 'ISO-10646-J-1';
  14423. case 'csunicode':
  14424. case 'iso10646ucs2':
  14425. return 'ISO-10646-UCS-2';
  14426. case 'csucs4':
  14427. case 'iso10646ucs4':
  14428. return 'ISO-10646-UCS-4';
  14429. case 'csunicodeascii':
  14430. case 'iso10646ucsbasic':
  14431. return 'ISO-10646-UCS-Basic';
  14432. case 'csunicodelatin1':
  14433. case 'iso10646':
  14434. case 'iso10646unicodelatin1':
  14435. return 'ISO-10646-Unicode-Latin1';
  14436. case 'csiso10646utf1':
  14437. case 'iso10646utf1':
  14438. return 'ISO-10646-UTF-1';
  14439. case 'csiso115481':
  14440. case 'iso115481':
  14441. case 'isotr115481':
  14442. return 'ISO-11548-1';
  14443. case 'csiso90':
  14444. case 'isoir90':
  14445. return 'iso-ir-90';
  14446. case 'csunicodeibm1261':
  14447. case 'isounicodeibm1261':
  14448. return 'ISO-Unicode-IBM-1261';
  14449. case 'csunicodeibm1264':
  14450. case 'isounicodeibm1264':
  14451. return 'ISO-Unicode-IBM-1264';
  14452. case 'csunicodeibm1265':
  14453. case 'isounicodeibm1265':
  14454. return 'ISO-Unicode-IBM-1265';
  14455. case 'csunicodeibm1268':
  14456. case 'isounicodeibm1268':
  14457. return 'ISO-Unicode-IBM-1268';
  14458. case 'csunicodeibm1276':
  14459. case 'isounicodeibm1276':
  14460. return 'ISO-Unicode-IBM-1276';
  14461. case 'csiso646basic1983':
  14462. case 'iso646basic1983':
  14463. case 'ref':
  14464. return 'ISO_646.basic:1983';
  14465. case 'csiso2intlrefversion':
  14466. case 'irv':
  14467. case 'iso646irv1983':
  14468. case 'isoir2':
  14469. return 'ISO_646.irv:1983';
  14470. case 'csiso2033':
  14471. case 'e13b':
  14472. case 'iso20331983':
  14473. case 'isoir98':
  14474. return 'ISO_2033-1983';
  14475. case 'csiso5427cyrillic':
  14476. case 'iso5427':
  14477. case 'isoir37':
  14478. return 'ISO_5427';
  14479. case 'iso5427cyrillic1981':
  14480. case 'iso54271981':
  14481. case 'isoir54':
  14482. return 'ISO_5427:1981';
  14483. case 'csiso5428greek':
  14484. case 'iso54281980':
  14485. case 'isoir55':
  14486. return 'ISO_5428:1980';
  14487. case 'csiso6937add':
  14488. case 'iso6937225':
  14489. case 'isoir152':
  14490. return 'ISO_6937-2-25';
  14491. case 'csisotextcomm':
  14492. case 'iso69372add':
  14493. case 'isoir142':
  14494. return 'ISO_6937-2-add';
  14495. case 'csiso8859supp':
  14496. case 'iso8859supp':
  14497. case 'isoir154':
  14498. case 'latin125':
  14499. return 'ISO_8859-supp';
  14500. case 'csiso10367box':
  14501. case 'iso10367box':
  14502. case 'isoir155':
  14503. return 'ISO_10367-box';
  14504. case 'csiso15italian':
  14505. case 'iso646it':
  14506. case 'isoir15':
  14507. case 'it':
  14508. return 'IT';
  14509. case 'csiso13jisc6220jp':
  14510. case 'isoir13':
  14511. case 'jisc62201969':
  14512. case 'jisc62201969jp':
  14513. case 'katakana':
  14514. case 'x2017':
  14515. return 'JIS_C6220-1969-jp';
  14516. case 'csiso14jisc6220ro':
  14517. case 'iso646jp':
  14518. case 'isoir14':
  14519. case 'jisc62201969ro':
  14520. case 'jp':
  14521. return 'JIS_C6220-1969-ro';
  14522. case 'csiso42jisc62261978':
  14523. case 'isoir42':
  14524. case 'jisc62261978':
  14525. return 'JIS_C6226-1978';
  14526. case 'csiso87jisx208':
  14527. case 'isoir87':
  14528. case 'jisc62261983':
  14529. case 'jisx2081983':
  14530. case 'x208':
  14531. return 'JIS_C6226-1983';
  14532. case 'csiso91jisc62291984a':
  14533. case 'isoir91':
  14534. case 'jisc62291984a':
  14535. case 'jpocra':
  14536. return 'JIS_C6229-1984-a';
  14537. case 'csiso92jisc62991984b':
  14538. case 'iso646jpocrb':
  14539. case 'isoir92':
  14540. case 'jisc62291984b':
  14541. case 'jpocrb':
  14542. return 'JIS_C6229-1984-b';
  14543. case 'csiso93jis62291984badd':
  14544. case 'isoir93':
  14545. case 'jisc62291984badd':
  14546. case 'jpocrbadd':
  14547. return 'JIS_C6229-1984-b-add';
  14548. case 'csiso94jis62291984hand':
  14549. case 'isoir94':
  14550. case 'jisc62291984hand':
  14551. case 'jpocrhand':
  14552. return 'JIS_C6229-1984-hand';
  14553. case 'csiso95jis62291984handadd':
  14554. case 'isoir95':
  14555. case 'jisc62291984handadd':
  14556. case 'jpocrhandadd':
  14557. return 'JIS_C6229-1984-hand-add';
  14558. case 'csiso96jisc62291984kana':
  14559. case 'isoir96':
  14560. case 'jisc62291984kana':
  14561. return 'JIS_C6229-1984-kana';
  14562. case 'csjisencoding':
  14563. case 'jisencoding':
  14564. return 'JIS_Encoding';
  14565. case 'cshalfwidthkatakana':
  14566. case 'jisx201':
  14567. case 'x201':
  14568. return 'JIS_X0201';
  14569. case 'csiso159jisx2121990':
  14570. case 'isoir159':
  14571. case 'jisx2121990':
  14572. case 'x212':
  14573. return 'JIS_X0212-1990';
  14574. case 'csiso141jusib1002':
  14575. case 'iso646yu':
  14576. case 'isoir141':
  14577. case 'js':
  14578. case 'jusib1002':
  14579. case 'yu':
  14580. return 'JUS_I.B1.002';
  14581. case 'csiso147macedonian':
  14582. case 'isoir147':
  14583. case 'jusib1003mac':
  14584. case 'macedonian':
  14585. return 'JUS_I.B1.003-mac';
  14586. case 'csiso146serbian':
  14587. case 'isoir146':
  14588. case 'jusib1003serb':
  14589. case 'serbian':
  14590. return 'JUS_I.B1.003-serb';
  14591. case 'koi7switched':
  14592. return 'KOI7-switched';
  14593. case 'cskoi8r':
  14594. case 'koi8r':
  14595. return 'KOI8-R';
  14596. case 'koi8u':
  14597. return 'KOI8-U';
  14598. case 'csksc5636':
  14599. case 'iso646kr':
  14600. case 'ksc5636':
  14601. return 'KSC5636';
  14602. case 'cskz1048':
  14603. case 'kz1048':
  14604. case 'rk1048':
  14605. case 'strk10482002':
  14606. return 'KZ-1048';
  14607. case 'csiso19latingreek':
  14608. case 'isoir19':
  14609. case 'latingreek':
  14610. return 'latin-greek';
  14611. case 'csiso27latingreek1':
  14612. case 'isoir27':
  14613. case 'latingreek1':
  14614. return 'Latin-greek-1';
  14615. case 'csiso158lap':
  14616. case 'isoir158':
  14617. case 'lap':
  14618. case 'latinlap':
  14619. return 'latin-lap';
  14620. case 'csmacintosh':
  14621. case 'mac':
  14622. case 'macintosh':
  14623. return 'macintosh';
  14624. case 'csmicrosoftpublishing':
  14625. case 'microsoftpublishing':
  14626. return 'Microsoft-Publishing';
  14627. case 'csmnem':
  14628. case 'mnem':
  14629. return 'MNEM';
  14630. case 'csmnemonic':
  14631. case 'mnemonic':
  14632. return 'MNEMONIC';
  14633. case 'csiso86hungarian':
  14634. case 'hu':
  14635. case 'iso646hu':
  14636. case 'isoir86':
  14637. case 'msz77953':
  14638. return 'MSZ_7795.3';
  14639. case 'csnatsdano':
  14640. case 'isoir91':
  14641. case 'natsdano':
  14642. return 'NATS-DANO';
  14643. case 'csnatsdanoadd':
  14644. case 'isoir92':
  14645. case 'natsdanoadd':
  14646. return 'NATS-DANO-ADD';
  14647. case 'csnatssefi':
  14648. case 'isoir81':
  14649. case 'natssefi':
  14650. return 'NATS-SEFI';
  14651. case 'csnatssefiadd':
  14652. case 'isoir82':
  14653. case 'natssefiadd':
  14654. return 'NATS-SEFI-ADD';
  14655. case 'csiso151cuba':
  14656. case 'cuba':
  14657. case 'iso646cu':
  14658. case 'isoir151':
  14659. case 'ncnc1081':
  14660. return 'NC_NC00-10:81';
  14661. case 'csiso69french':
  14662. case 'fr':
  14663. case 'iso646fr':
  14664. case 'isoir69':
  14665. case 'nfz62010':
  14666. return 'NF_Z_62-010';
  14667. case 'csiso25french':
  14668. case 'iso646fr1':
  14669. case 'isoir25':
  14670. case 'nfz620101973':
  14671. return 'NF_Z_62-010_(1973)';
  14672. case 'csiso60danishnorwegian':
  14673. case 'csiso60norwegian1':
  14674. case 'iso646no':
  14675. case 'isoir60':
  14676. case 'no':
  14677. case 'ns45511':
  14678. return 'NS_4551-1';
  14679. case 'csiso61norwegian2':
  14680. case 'iso646no2':
  14681. case 'isoir61':
  14682. case 'no2':
  14683. case 'ns45512':
  14684. return 'NS_4551-2';
  14685. case 'osdebcdicdf3irv':
  14686. return 'OSD_EBCDIC_DF03_IRV';
  14687. case 'osdebcdicdf41':
  14688. return 'OSD_EBCDIC_DF04_1';
  14689. case 'osdebcdicdf415':
  14690. return 'OSD_EBCDIC_DF04_15';
  14691. case 'cspc8danishnorwegian':
  14692. case 'pc8danishnorwegian':
  14693. return 'PC8-Danish-Norwegian';
  14694. case 'cspc8turkish':
  14695. case 'pc8turkish':
  14696. return 'PC8-Turkish';
  14697. case 'csiso16portuguese':
  14698. case 'iso646pt':
  14699. case 'isoir16':
  14700. case 'pt':
  14701. return 'PT';
  14702. case 'csiso84portuguese2':
  14703. case 'iso646pt2':
  14704. case 'isoir84':
  14705. case 'pt2':
  14706. return 'PT2';
  14707. case 'cp154':
  14708. case 'csptcp154':
  14709. case 'cyrillicasian':
  14710. case 'pt154':
  14711. case 'ptcp154':
  14712. return 'PTCP154';
  14713. case 'scsu':
  14714. return 'SCSU';
  14715. case 'csiso10swedish':
  14716. case 'fi':
  14717. case 'iso646fi':
  14718. case 'iso646se':
  14719. case 'isoir10':
  14720. case 'se':
  14721. case 'sen850200b':
  14722. return 'SEN_850200_B';
  14723. case 'csiso11swedishfornames':
  14724. case 'iso646se2':
  14725. case 'isoir11':
  14726. case 'se2':
  14727. case 'sen850200c':
  14728. return 'SEN_850200_C';
  14729. case 'csiso102t617bit':
  14730. case 'isoir102':
  14731. case 't617bit':
  14732. return 'T.61-7bit';
  14733. case 'csiso103t618bit':
  14734. case 'isoir103':
  14735. case 't61':
  14736. case 't618bit':
  14737. return 'T.61-8bit';
  14738. case 'csiso128t101g2':
  14739. case 'isoir128':
  14740. case 't101g2':
  14741. return 'T.101-G2';
  14742. case 'cstscii':
  14743. case 'tscii':
  14744. return 'TSCII';
  14745. case 'csunicode11':
  14746. case 'unicode11':
  14747. return 'UNICODE-1-1';
  14748. case 'csunicode11utf7':
  14749. case 'unicode11utf7':
  14750. return 'UNICODE-1-1-UTF-7';
  14751. case 'csunknown8bit':
  14752. case 'unknown8bit':
  14753. return 'UNKNOWN-8BIT';
  14754. case 'ansix341968':
  14755. case 'ansix341986':
  14756. case 'ascii':
  14757. case 'cp367':
  14758. case 'csascii':
  14759. case 'ibm367':
  14760. case 'iso646irv1991':
  14761. case 'iso646us':
  14762. case 'isoir6':
  14763. case 'us':
  14764. case 'usascii':
  14765. return 'US-ASCII';
  14766. case 'csusdk':
  14767. case 'usdk':
  14768. return 'us-dk';
  14769. case 'utf7':
  14770. return 'UTF-7';
  14771. case 'utf8':
  14772. return 'UTF-8';
  14773. case 'utf16':
  14774. return 'UTF-16';
  14775. case 'utf16be':
  14776. return 'UTF-16BE';
  14777. case 'utf16le':
  14778. return 'UTF-16LE';
  14779. case 'utf32':
  14780. return 'UTF-32';
  14781. case 'utf32be':
  14782. return 'UTF-32BE';
  14783. case 'utf32le':
  14784. return 'UTF-32LE';
  14785. case 'csventurainternational':
  14786. case 'venturainternational':
  14787. return 'Ventura-International';
  14788. case 'csventuramath':
  14789. case 'venturamath':
  14790. return 'Ventura-Math';
  14791. case 'csventuraus':
  14792. case 'venturaus':
  14793. return 'Ventura-US';
  14794. case 'csiso70videotexsupp1':
  14795. case 'isoir70':
  14796. case 'videotexsuppl':
  14797. return 'videotex-suppl';
  14798. case 'csviqr':
  14799. case 'viqr':
  14800. return 'VIQR';
  14801. case 'csviscii':
  14802. case 'viscii':
  14803. return 'VISCII';
  14804. case 'csshiftjis':
  14805. case 'cswindows31j':
  14806. case 'mskanji':
  14807. case 'shiftjis':
  14808. case 'windows31j':
  14809. return 'Windows-31J';
  14810. case 'iso885911':
  14811. case 'tis620':
  14812. return 'windows-874';
  14813. case 'cseuckr':
  14814. case 'csksc56011987':
  14815. case 'euckr':
  14816. case 'isoir149':
  14817. case 'korean':
  14818. case 'ksc5601':
  14819. case 'ksc56011987':
  14820. case 'ksc56011989':
  14821. case 'windows949':
  14822. return 'windows-949';
  14823. case 'windows1250':
  14824. return 'windows-1250';
  14825. case 'windows1251':
  14826. return 'windows-1251';
  14827. case 'cp819':
  14828. case 'csisolatin1':
  14829. case 'ibm819':
  14830. case 'iso88591':
  14831. case 'iso885911987':
  14832. case 'isoir100':
  14833. case 'l1':
  14834. case 'latin1':
  14835. case 'windows1252':
  14836. return 'windows-1252';
  14837. case 'windows1253':
  14838. return 'windows-1253';
  14839. case 'csisolatin5':
  14840. case 'iso88599':
  14841. case 'iso885991989':
  14842. case 'isoir148':
  14843. case 'l5':
  14844. case 'latin5':
  14845. case 'windows1254':
  14846. return 'windows-1254';
  14847. case 'windows1255':
  14848. return 'windows-1255';
  14849. case 'windows1256':
  14850. return 'windows-1256';
  14851. case 'windows1257':
  14852. return 'windows-1257';
  14853. case 'windows1258':
  14854. return 'windows-1258';
  14855. default:
  14856. return $charset;
  14857. }
  14858. }
  14859. public static function get_curl_version()
  14860. {
  14861. if (is_array($curl = curl_version()))
  14862. {
  14863. $curl = $curl['version'];
  14864. }
  14865. elseif (substr($curl, 0, 5) === 'curl/')
  14866. {
  14867. $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
  14868. }
  14869. elseif (substr($curl, 0, 8) === 'libcurl/')
  14870. {
  14871. $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
  14872. }
  14873. else
  14874. {
  14875. $curl = 0;
  14876. }
  14877. return $curl;
  14878. }
  14879. /**
  14880. * Strip HTML comments
  14881. *
  14882. * @param string $data Data to strip comments from
  14883. * @return string Comment stripped string
  14884. */
  14885. public static function strip_comments($data)
  14886. {
  14887. $output = '';
  14888. while (($start = strpos($data, '<!--')) !== false)
  14889. {
  14890. $output .= substr($data, 0, $start);
  14891. if (($end = strpos($data, '-->', $start)) !== false)
  14892. {
  14893. $data = substr_replace($data, '', 0, $end + 3);
  14894. }
  14895. else
  14896. {
  14897. $data = '';
  14898. }
  14899. }
  14900. return $output . $data;
  14901. }
  14902. public static function parse_date($dt)
  14903. {
  14904. $parser = SimplePie_Parse_Date::get();
  14905. return $parser->parse($dt);
  14906. }
  14907. /**
  14908. * Decode HTML entities
  14909. *
  14910. * @deprecated Use DOMDocument instead
  14911. * @param string $data Input data
  14912. * @return string Output data
  14913. */
  14914. public static function entities_decode($data)
  14915. {
  14916. $decoder = new SimplePie_Decode_HTML_Entities($data);
  14917. return $decoder->parse();
  14918. }
  14919. /**
  14920. * Remove RFC822 comments
  14921. *
  14922. * @param string $data Data to strip comments from
  14923. * @return string Comment stripped string
  14924. */
  14925. public static function uncomment_rfc822($string)
  14926. {
  14927. $string = (string) $string;
  14928. $position = 0;
  14929. $length = strlen($string);
  14930. $depth = 0;
  14931. $output = '';
  14932. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  14933. {
  14934. $output .= substr($string, $position, $pos - $position);
  14935. $position = $pos + 1;
  14936. if ($string[$pos - 1] !== '\\')
  14937. {
  14938. $depth++;
  14939. while ($depth && $position < $length)
  14940. {
  14941. $position += strcspn($string, '()', $position);
  14942. if ($string[$position - 1] === '\\')
  14943. {
  14944. $position++;
  14945. continue;
  14946. }
  14947. elseif (isset($string[$position]))
  14948. {
  14949. switch ($string[$position])
  14950. {
  14951. case '(':
  14952. $depth++;
  14953. break;
  14954. case ')':
  14955. $depth--;
  14956. break;
  14957. }
  14958. $position++;
  14959. }
  14960. else
  14961. {
  14962. break;
  14963. }
  14964. }
  14965. }
  14966. else
  14967. {
  14968. $output .= '(';
  14969. }
  14970. }
  14971. $output .= substr($string, $position);
  14972. return $output;
  14973. }
  14974. public static function parse_mime($mime)
  14975. {
  14976. if (($pos = strpos($mime, ';')) === false)
  14977. {
  14978. return trim($mime);
  14979. }
  14980. else
  14981. {
  14982. return trim(substr($mime, 0, $pos));
  14983. }
  14984. }
  14985. public static function atom_03_construct_type($attribs)
  14986. {
  14987. if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
  14988. {
  14989. $mode = SIMPLEPIE_CONSTRUCT_BASE64;
  14990. }
  14991. else
  14992. {
  14993. $mode = SIMPLEPIE_CONSTRUCT_NONE;
  14994. }
  14995. if (isset($attribs['']['type']))
  14996. {
  14997. switch (strtolower(trim($attribs['']['type'])))
  14998. {
  14999. case 'text':
  15000. case 'text/plain':
  15001. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  15002. case 'html':
  15003. case 'text/html':
  15004. return SIMPLEPIE_CONSTRUCT_HTML | $mode;
  15005. case 'xhtml':
  15006. case 'application/xhtml+xml':
  15007. return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
  15008. default:
  15009. return SIMPLEPIE_CONSTRUCT_NONE | $mode;
  15010. }
  15011. }
  15012. else
  15013. {
  15014. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  15015. }
  15016. }
  15017. public static function atom_10_construct_type($attribs)
  15018. {
  15019. if (isset($attribs['']['type']))
  15020. {
  15021. switch (strtolower(trim($attribs['']['type'])))
  15022. {
  15023. case 'text':
  15024. return SIMPLEPIE_CONSTRUCT_TEXT;
  15025. case 'html':
  15026. return SIMPLEPIE_CONSTRUCT_HTML;
  15027. case 'xhtml':
  15028. return SIMPLEPIE_CONSTRUCT_XHTML;
  15029. default:
  15030. return SIMPLEPIE_CONSTRUCT_NONE;
  15031. }
  15032. }
  15033. return SIMPLEPIE_CONSTRUCT_TEXT;
  15034. }
  15035. public static function atom_10_content_construct_type($attribs)
  15036. {
  15037. if (isset($attribs['']['type']))
  15038. {
  15039. $type = strtolower(trim($attribs['']['type']));
  15040. switch ($type)
  15041. {
  15042. case 'text':
  15043. return SIMPLEPIE_CONSTRUCT_TEXT;
  15044. case 'html':
  15045. return SIMPLEPIE_CONSTRUCT_HTML;
  15046. case 'xhtml':
  15047. return SIMPLEPIE_CONSTRUCT_XHTML;
  15048. }
  15049. if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
  15050. {
  15051. return SIMPLEPIE_CONSTRUCT_NONE;
  15052. }
  15053. else
  15054. {
  15055. return SIMPLEPIE_CONSTRUCT_BASE64;
  15056. }
  15057. }
  15058. else
  15059. {
  15060. return SIMPLEPIE_CONSTRUCT_TEXT;
  15061. }
  15062. }
  15063. public static function is_isegment_nz_nc($string)
  15064. {
  15065. 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);
  15066. }
  15067. public static function space_seperated_tokens($string)
  15068. {
  15069. $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
  15070. $string_length = strlen($string);
  15071. $position = strspn($string, $space_characters);
  15072. $tokens = array();
  15073. while ($position < $string_length)
  15074. {
  15075. $len = strcspn($string, $space_characters, $position);
  15076. $tokens[] = substr($string, $position, $len);
  15077. $position += $len;
  15078. $position += strspn($string, $space_characters, $position);
  15079. }
  15080. return $tokens;
  15081. }
  15082. /**
  15083. * Converts a unicode codepoint to a UTF-8 character
  15084. *
  15085. * @static
  15086. * @param int $codepoint Unicode codepoint
  15087. * @return string UTF-8 character
  15088. */
  15089. public static function codepoint_to_utf8($codepoint)
  15090. {
  15091. $codepoint = (int) $codepoint;
  15092. if ($codepoint < 0)
  15093. {
  15094. return false;
  15095. }
  15096. else if ($codepoint <= 0x7f)
  15097. {
  15098. return chr($codepoint);
  15099. }
  15100. else if ($codepoint <= 0x7ff)
  15101. {
  15102. return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
  15103. }
  15104. else if ($codepoint <= 0xffff)
  15105. {
  15106. return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  15107. }
  15108. else if ($codepoint <= 0x10ffff)
  15109. {
  15110. return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  15111. }
  15112. else
  15113. {
  15114. // U+FFFD REPLACEMENT CHARACTER
  15115. return "\xEF\xBF\xBD";
  15116. }
  15117. }
  15118. /**
  15119. * Similar to parse_str()
  15120. *
  15121. * Returns an associative array of name/value pairs, where the value is an
  15122. * array of values that have used the same name
  15123. *
  15124. * @static
  15125. * @param string $str The input string.
  15126. * @return array
  15127. */
  15128. public static function parse_str($str)
  15129. {
  15130. $return = array();
  15131. $str = explode('&', $str);
  15132. foreach ($str as $section)
  15133. {
  15134. if (strpos($section, '=') !== false)
  15135. {
  15136. list($name, $value) = explode('=', $section, 2);
  15137. $return[urldecode($name)][] = urldecode($value);
  15138. }
  15139. else
  15140. {
  15141. $return[urldecode($section)][] = null;
  15142. }
  15143. }
  15144. return $return;
  15145. }
  15146. /**
  15147. * Detect XML encoding, as per XML 1.0 Appendix F.1
  15148. *
  15149. * @todo Add support for EBCDIC
  15150. * @param string $data XML data
  15151. * @param SimplePie_Registry $registry Class registry
  15152. * @return array Possible encodings
  15153. */
  15154. public static function xml_encoding($data, $registry)
  15155. {
  15156. // UTF-32 Big Endian BOM
  15157. if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
  15158. {
  15159. $encoding[] = 'UTF-32BE';
  15160. }
  15161. // UTF-32 Little Endian BOM
  15162. elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
  15163. {
  15164. $encoding[] = 'UTF-32LE';
  15165. }
  15166. // UTF-16 Big Endian BOM
  15167. elseif (substr($data, 0, 2) === "\xFE\xFF")
  15168. {
  15169. $encoding[] = 'UTF-16BE';
  15170. }
  15171. // UTF-16 Little Endian BOM
  15172. elseif (substr($data, 0, 2) === "\xFF\xFE")
  15173. {
  15174. $encoding[] = 'UTF-16LE';
  15175. }
  15176. // UTF-8 BOM
  15177. elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
  15178. {
  15179. $encoding[] = 'UTF-8';
  15180. }
  15181. // UTF-32 Big Endian Without BOM
  15182. elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C")
  15183. {
  15184. if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
  15185. {
  15186. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
  15187. if ($parser->parse())
  15188. {
  15189. $encoding[] = $parser->encoding;
  15190. }
  15191. }
  15192. $encoding[] = 'UTF-32BE';
  15193. }
  15194. // UTF-32 Little Endian Without BOM
  15195. elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00")
  15196. {
  15197. if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
  15198. {
  15199. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
  15200. if ($parser->parse())
  15201. {
  15202. $encoding[] = $parser->encoding;
  15203. }
  15204. }
  15205. $encoding[] = 'UTF-32LE';
  15206. }
  15207. // UTF-16 Big Endian Without BOM
  15208. elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
  15209. {
  15210. if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
  15211. {
  15212. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
  15213. if ($parser->parse())
  15214. {
  15215. $encoding[] = $parser->encoding;
  15216. }
  15217. }
  15218. $encoding[] = 'UTF-16BE';
  15219. }
  15220. // UTF-16 Little Endian Without BOM
  15221. elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
  15222. {
  15223. if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
  15224. {
  15225. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
  15226. if ($parser->parse())
  15227. {
  15228. $encoding[] = $parser->encoding;
  15229. }
  15230. }
  15231. $encoding[] = 'UTF-16LE';
  15232. }
  15233. // US-ASCII (or superset)
  15234. elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
  15235. {
  15236. if ($pos = strpos($data, "\x3F\x3E"))
  15237. {
  15238. $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
  15239. if ($parser->parse())
  15240. {
  15241. $encoding[] = $parser->encoding;
  15242. }
  15243. }
  15244. $encoding[] = 'UTF-8';
  15245. }
  15246. // Fallback to UTF-8
  15247. else
  15248. {
  15249. $encoding[] = 'UTF-8';
  15250. }
  15251. return $encoding;
  15252. }
  15253. public static function output_javascript()
  15254. {
  15255. if (function_exists('ob_gzhandler'))
  15256. {
  15257. ob_start('ob_gzhandler');
  15258. }
  15259. header('Content-type: text/javascript; charset: UTF-8');
  15260. header('Cache-Control: must-revalidate');
  15261. header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
  15262. ?>
  15263. function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
  15264. if (placeholder != '') {
  15265. document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
  15266. }
  15267. else {
  15268. document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
  15269. }
  15270. }
  15271. function embed_flash(bgcolor, width, height, link, loop, type) {
  15272. document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
  15273. }
  15274. function embed_flv(width, height, link, placeholder, loop, player) {
  15275. document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>');
  15276. }
  15277. function embed_wmedia(width, height, link) {
  15278. document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
  15279. }
  15280. <?php
  15281. }
  15282. /**
  15283. * Get the SimplePie build timestamp
  15284. *
  15285. * Uses the git index if it exists, otherwise uses the modification time
  15286. * of the newest file.
  15287. */
  15288. public static function get_build()
  15289. {
  15290. $root = dirname(dirname(__FILE__));
  15291. if (file_exists($root . '/.git/index'))
  15292. {
  15293. return filemtime($root . '/.git/index');
  15294. }
  15295. elseif (file_exists($root . '/SimplePie'))
  15296. {
  15297. $time = 0;
  15298. foreach (glob($root . '/SimplePie/*.php') as $file)
  15299. {
  15300. if (($mtime = filemtime($file)) > $time)
  15301. {
  15302. $time = $mtime;
  15303. }
  15304. }
  15305. return $time;
  15306. }
  15307. elseif (file_exists(dirname(__FILE__) . '/Core.php'))
  15308. {
  15309. return filemtime(dirname(__FILE__) . '/Core.php');
  15310. }
  15311. else
  15312. {
  15313. return filemtime(__FILE__);
  15314. }
  15315. }
  15316. /**
  15317. * Format debugging information
  15318. */
  15319. public static function debug(&$sp)
  15320. {
  15321. $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
  15322. $info .= 'PHP ' . PHP_VERSION . "\n";
  15323. if ($sp->error() !== null)
  15324. {
  15325. $info .= 'Error occurred: ' . $sp->error() . "\n";
  15326. }
  15327. else
  15328. {
  15329. $info .= "No error found.\n";
  15330. }
  15331. $info .= "Extensions:\n";
  15332. $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
  15333. foreach ($extensions as $ext)
  15334. {
  15335. if (extension_loaded($ext))
  15336. {
  15337. $info .= " $ext loaded\n";
  15338. switch ($ext)
  15339. {
  15340. case 'pcre':
  15341. $info .= ' Version ' . PCRE_VERSION . "\n";
  15342. break;
  15343. case 'curl':
  15344. $version = curl_version();
  15345. $info .= ' Version ' . $version['version'] . "\n";
  15346. break;
  15347. case 'mbstring':
  15348. $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
  15349. break;
  15350. case 'iconv':
  15351. $info .= ' Version ' . ICONV_VERSION . "\n";
  15352. break;
  15353. case 'xml':
  15354. $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
  15355. break;
  15356. }
  15357. }
  15358. else
  15359. {
  15360. $info .= " $ext not loaded\n";
  15361. }
  15362. }
  15363. return $info;
  15364. }
  15365. public static function silence_errors($num, $str)
  15366. {
  15367. // No-op
  15368. }
  15369. }
  15370. /**
  15371. * Parses XML into something sane
  15372. *
  15373. *
  15374. * This class can be overloaded with {@see SimplePie::set_parser_class()}
  15375. *
  15376. * @package SimplePie
  15377. * @subpackage Parsing
  15378. */
  15379. class SimplePie_Parser
  15380. {
  15381. var $error_code;
  15382. var $error_string;
  15383. var $current_line;
  15384. var $current_column;
  15385. var $current_byte;
  15386. var $separator = ' ';
  15387. var $namespace = array('');
  15388. var $element = array('');
  15389. var $xml_base = array('');
  15390. var $xml_base_explicit = array(false);
  15391. var $xml_lang = array('');
  15392. var $data = array();
  15393. var $datas = array(array());
  15394. var $current_xhtml_construct = -1;
  15395. var $encoding;
  15396. protected $registry;
  15397. public function set_registry(SimplePie_Registry $registry)
  15398. {
  15399. $this->registry = $registry;
  15400. }
  15401. public function parse(&$data, $encoding)
  15402. {
  15403. // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
  15404. if (strtoupper($encoding) === 'US-ASCII')
  15405. {
  15406. $this->encoding = 'UTF-8';
  15407. }
  15408. else
  15409. {
  15410. $this->encoding = $encoding;
  15411. }
  15412. // Strip BOM:
  15413. // UTF-32 Big Endian BOM
  15414. if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
  15415. {
  15416. $data = substr($data, 4);
  15417. }
  15418. // UTF-32 Little Endian BOM
  15419. elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
  15420. {
  15421. $data = substr($data, 4);
  15422. }
  15423. // UTF-16 Big Endian BOM
  15424. elseif (substr($data, 0, 2) === "\xFE\xFF")
  15425. {
  15426. $data = substr($data, 2);
  15427. }
  15428. // UTF-16 Little Endian BOM
  15429. elseif (substr($data, 0, 2) === "\xFF\xFE")
  15430. {
  15431. $data = substr($data, 2);
  15432. }
  15433. // UTF-8 BOM
  15434. elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
  15435. {
  15436. $data = substr($data, 3);
  15437. }
  15438. if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
  15439. {
  15440. $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
  15441. if ($declaration->parse())
  15442. {
  15443. $data = substr($data, $pos + 2);
  15444. $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
  15445. }
  15446. else
  15447. {
  15448. $this->error_string = 'SimplePie bug! Please report this!';
  15449. return false;
  15450. }
  15451. }
  15452. $return = true;
  15453. static $xml_is_sane = null;
  15454. if ($xml_is_sane === null)
  15455. {
  15456. $parser_check = xml_parser_create();
  15457. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  15458. xml_parser_free($parser_check);
  15459. $xml_is_sane = isset($values[0]['value']);
  15460. }
  15461. // Create the parser
  15462. if ($xml_is_sane)
  15463. {
  15464. $xml = xml_parser_create_ns($this->encoding, $this->separator);
  15465. xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
  15466. xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
  15467. xml_set_object($xml, $this);
  15468. xml_set_character_data_handler($xml, 'cdata');
  15469. xml_set_element_handler($xml, 'tag_open', 'tag_close');
  15470. // Parse!
  15471. if (!xml_parse($xml, $data, true))
  15472. {
  15473. $this->error_code = xml_get_error_code($xml);
  15474. $this->error_string = xml_error_string($this->error_code);
  15475. $return = false;
  15476. }
  15477. $this->current_line = xml_get_current_line_number($xml);
  15478. $this->current_column = xml_get_current_column_number($xml);
  15479. $this->current_byte = xml_get_current_byte_index($xml);
  15480. xml_parser_free($xml);
  15481. return $return;
  15482. }
  15483. else
  15484. {
  15485. libxml_clear_errors();
  15486. $xml = new XMLReader();
  15487. $xml->xml($data);
  15488. while (@$xml->read())
  15489. {
  15490. switch ($xml->nodeType)
  15491. {
  15492. case constant('XMLReader::END_ELEMENT'):
  15493. if ($xml->namespaceURI !== '')
  15494. {
  15495. $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
  15496. }
  15497. else
  15498. {
  15499. $tagName = $xml->localName;
  15500. }
  15501. $this->tag_close(null, $tagName);
  15502. break;
  15503. case constant('XMLReader::ELEMENT'):
  15504. $empty = $xml->isEmptyElement;
  15505. if ($xml->namespaceURI !== '')
  15506. {
  15507. $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
  15508. }
  15509. else
  15510. {
  15511. $tagName = $xml->localName;
  15512. }
  15513. $attributes = array();
  15514. while ($xml->moveToNextAttribute())
  15515. {
  15516. if ($xml->namespaceURI !== '')
  15517. {
  15518. $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
  15519. }
  15520. else
  15521. {
  15522. $attrName = $xml->localName;
  15523. }
  15524. $attributes[$attrName] = $xml->value;
  15525. }
  15526. $this->tag_open(null, $tagName, $attributes);
  15527. if ($empty)
  15528. {
  15529. $this->tag_close(null, $tagName);
  15530. }
  15531. break;
  15532. case constant('XMLReader::TEXT'):
  15533. case constant('XMLReader::CDATA'):
  15534. $this->cdata(null, $xml->value);
  15535. break;
  15536. }
  15537. }
  15538. if ($error = libxml_get_last_error())
  15539. {
  15540. $this->error_code = $error->code;
  15541. $this->error_string = $error->message;
  15542. $this->current_line = $error->line;
  15543. $this->current_column = $error->column;
  15544. return false;
  15545. }
  15546. else
  15547. {
  15548. return true;
  15549. }
  15550. }
  15551. }
  15552. public function get_error_code()
  15553. {
  15554. return $this->error_code;
  15555. }
  15556. public function get_error_string()
  15557. {
  15558. return $this->error_string;
  15559. }
  15560. public function get_current_line()
  15561. {
  15562. return $this->current_line;
  15563. }
  15564. public function get_current_column()
  15565. {
  15566. return $this->current_column;
  15567. }
  15568. public function get_current_byte()
  15569. {
  15570. return $this->current_byte;
  15571. }
  15572. public function get_data()
  15573. {
  15574. return $this->data;
  15575. }
  15576. public function tag_open($parser, $tag, $attributes)
  15577. {
  15578. list($this->namespace[], $this->element[]) = $this->split_ns($tag);
  15579. $attribs = array();
  15580. foreach ($attributes as $name => $value)
  15581. {
  15582. list($attrib_namespace, $attribute) = $this->split_ns($name);
  15583. $attribs[$attrib_namespace][$attribute] = $value;
  15584. }
  15585. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
  15586. {
  15587. $this->xml_base[] = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
  15588. $this->xml_base_explicit[] = true;
  15589. }
  15590. else
  15591. {
  15592. $this->xml_base[] = end($this->xml_base);
  15593. $this->xml_base_explicit[] = end($this->xml_base_explicit);
  15594. }
  15595. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
  15596. {
  15597. $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
  15598. }
  15599. else
  15600. {
  15601. $this->xml_lang[] = end($this->xml_lang);
  15602. }
  15603. if ($this->current_xhtml_construct >= 0)
  15604. {
  15605. $this->current_xhtml_construct++;
  15606. if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
  15607. {
  15608. $this->data['data'] .= '<' . end($this->element);
  15609. if (isset($attribs['']))
  15610. {
  15611. foreach ($attribs[''] as $name => $value)
  15612. {
  15613. $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
  15614. }
  15615. }
  15616. $this->data['data'] .= '>';
  15617. }
  15618. }
  15619. else
  15620. {
  15621. $this->datas[] =& $this->data;
  15622. $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
  15623. $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));
  15624. 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')
  15625. || (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')
  15626. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
  15627. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
  15628. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
  15629. {
  15630. $this->current_xhtml_construct = 0;
  15631. }
  15632. }
  15633. }
  15634. public function cdata($parser, $cdata)
  15635. {
  15636. if ($this->current_xhtml_construct >= 0)
  15637. {
  15638. $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
  15639. }
  15640. else
  15641. {
  15642. $this->data['data'] .= $cdata;
  15643. }
  15644. }
  15645. public function tag_close($parser, $tag)
  15646. {
  15647. if ($this->current_xhtml_construct >= 0)
  15648. {
  15649. $this->current_xhtml_construct--;
  15650. 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')))
  15651. {
  15652. $this->data['data'] .= '</' . end($this->element) . '>';
  15653. }
  15654. }
  15655. if ($this->current_xhtml_construct === -1)
  15656. {
  15657. $this->data =& $this->datas[count($this->datas) - 1];
  15658. array_pop($this->datas);
  15659. }
  15660. array_pop($this->element);
  15661. array_pop($this->namespace);
  15662. array_pop($this->xml_base);
  15663. array_pop($this->xml_base_explicit);
  15664. array_pop($this->xml_lang);
  15665. }
  15666. public function split_ns($string)
  15667. {
  15668. static $cache = array();
  15669. if (!isset($cache[$string]))
  15670. {
  15671. if ($pos = strpos($string, $this->separator))
  15672. {
  15673. static $separator_length;
  15674. if (!$separator_length)
  15675. {
  15676. $separator_length = strlen($this->separator);
  15677. }
  15678. $namespace = substr($string, 0, $pos);
  15679. $local_name = substr($string, $pos + $separator_length);
  15680. if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
  15681. {
  15682. $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
  15683. }
  15684. // Normalize the Media RSS namespaces
  15685. if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
  15686. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
  15687. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
  15688. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
  15689. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
  15690. {
  15691. $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
  15692. }
  15693. $cache[$string] = array($namespace, $local_name);
  15694. }
  15695. else
  15696. {
  15697. $cache[$string] = array('', $string);
  15698. }
  15699. }
  15700. return $cache[$string];
  15701. }
  15702. }
  15703. /**
  15704. * Decode HTML Entities
  15705. *
  15706. * This implements HTML5 as of revision 967 (2007-06-28)
  15707. *
  15708. * @deprecated Use DOMDocument instead!
  15709. * @package SimplePie
  15710. */
  15711. class SimplePie_Decode_HTML_Entities
  15712. {
  15713. /**
  15714. * Data to be parsed
  15715. *
  15716. * @access private
  15717. * @var string
  15718. */
  15719. var $data = '';
  15720. /**
  15721. * Currently consumed bytes
  15722. *
  15723. * @access private
  15724. * @var string
  15725. */
  15726. var $consumed = '';
  15727. /**
  15728. * Position of the current byte being parsed
  15729. *
  15730. * @access private
  15731. * @var int
  15732. */
  15733. var $position = 0;
  15734. /**
  15735. * Create an instance of the class with the input data
  15736. *
  15737. * @access public
  15738. * @param string $data Input data
  15739. */
  15740. public function __construct($data)
  15741. {
  15742. $this->data = $data;
  15743. }
  15744. /**
  15745. * Parse the input data
  15746. *
  15747. * @access public
  15748. * @return string Output data
  15749. */
  15750. public function parse()
  15751. {
  15752. while (($this->position = strpos($this->data, '&', $this->position)) !== false)
  15753. {
  15754. $this->consume();
  15755. $this->entity();
  15756. $this->consumed = '';
  15757. }
  15758. return $this->data;
  15759. }
  15760. /**
  15761. * Consume the next byte
  15762. *
  15763. * @access private
  15764. * @return mixed The next byte, or false, if there is no more data
  15765. */
  15766. public function consume()
  15767. {
  15768. if (isset($this->data[$this->position]))
  15769. {
  15770. $this->consumed .= $this->data[$this->position];
  15771. return $this->data[$this->position++];
  15772. }
  15773. else
  15774. {
  15775. return false;
  15776. }
  15777. }
  15778. /**
  15779. * Consume a range of characters
  15780. *
  15781. * @access private
  15782. * @param string $chars Characters to consume
  15783. * @return mixed A series of characters that match the range, or false
  15784. */
  15785. public function consume_range($chars)
  15786. {
  15787. if ($len = strspn($this->data, $chars, $this->position))
  15788. {
  15789. $data = substr($this->data, $this->position, $len);
  15790. $this->consumed .= $data;
  15791. $this->position += $len;
  15792. return $data;
  15793. }
  15794. else
  15795. {
  15796. return false;
  15797. }
  15798. }
  15799. /**
  15800. * Unconsume one byte
  15801. *
  15802. * @access private
  15803. */
  15804. public function unconsume()
  15805. {
  15806. $this->consumed = substr($this->consumed, 0, -1);
  15807. $this->position--;
  15808. }
  15809. /**
  15810. * Decode an entity
  15811. *
  15812. * @access private
  15813. */
  15814. public function entity()
  15815. {
  15816. switch ($this->consume())
  15817. {
  15818. case "\x09":
  15819. case "\x0A":
  15820. case "\x0B":
  15821. case "\x0B":
  15822. case "\x0C":
  15823. case "\x20":
  15824. case "\x3C":
  15825. case "\x26":
  15826. case false:
  15827. break;
  15828. case "\x23":
  15829. switch ($this->consume())
  15830. {
  15831. case "\x78":
  15832. case "\x58":
  15833. $range = '0123456789ABCDEFabcdef';
  15834. $hex = true;
  15835. break;
  15836. default:
  15837. $range = '0123456789';
  15838. $hex = false;
  15839. $this->unconsume();
  15840. break;
  15841. }
  15842. if ($codepoint = $this->consume_range($range))
  15843. {
  15844. 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");
  15845. if ($hex)
  15846. {
  15847. $codepoint = hexdec($codepoint);
  15848. }
  15849. else
  15850. {
  15851. $codepoint = intval($codepoint);
  15852. }
  15853. if (isset($windows_1252_specials[$codepoint]))
  15854. {
  15855. $replacement = $windows_1252_specials[$codepoint];
  15856. }
  15857. else
  15858. {
  15859. $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
  15860. }
  15861. if (!in_array($this->consume(), array(';', false), true))
  15862. {
  15863. $this->unconsume();
  15864. }
  15865. $consumed_length = strlen($this->consumed);
  15866. $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
  15867. $this->position += strlen($replacement) - $consumed_length;
  15868. }
  15869. break;
  15870. default:
  15871. static $entities = array(
  15872. 'Aacute' => "\xC3\x81",
  15873. 'aacute' => "\xC3\xA1",
  15874. 'Aacute;' => "\xC3\x81",
  15875. 'aacute;' => "\xC3\xA1",
  15876. 'Acirc' => "\xC3\x82",
  15877. 'acirc' => "\xC3\xA2",
  15878. 'Acirc;' => "\xC3\x82",
  15879. 'acirc;' => "\xC3\xA2",
  15880. 'acute' => "\xC2\xB4",
  15881. 'acute;' => "\xC2\xB4",
  15882. 'AElig' => "\xC3\x86",
  15883. 'aelig' => "\xC3\xA6",
  15884. 'AElig;' => "\xC3\x86",
  15885. 'aelig;' => "\xC3\xA6",
  15886. 'Agrave' => "\xC3\x80",
  15887. 'agrave' => "\xC3\xA0",
  15888. 'Agrave;' => "\xC3\x80",
  15889. 'agrave;' => "\xC3\xA0",
  15890. 'alefsym;' => "\xE2\x84\xB5",
  15891. 'Alpha;' => "\xCE\x91",
  15892. 'alpha;' => "\xCE\xB1",
  15893. 'AMP' => "\x26",
  15894. 'amp' => "\x26",
  15895. 'AMP;' => "\x26",
  15896. 'amp;' => "\x26",
  15897. 'and;' => "\xE2\x88\xA7",
  15898. 'ang;' => "\xE2\x88\xA0",
  15899. 'apos;' => "\x27",
  15900. 'Aring' => "\xC3\x85",
  15901. 'aring' => "\xC3\xA5",
  15902. 'Aring;' => "\xC3\x85",
  15903. 'aring;' => "\xC3\xA5",
  15904. 'asymp;' => "\xE2\x89\x88",
  15905. 'Atilde' => "\xC3\x83",
  15906. 'atilde' => "\xC3\xA3",
  15907. 'Atilde;' => "\xC3\x83",
  15908. 'atilde;' => "\xC3\xA3",
  15909. 'Auml' => "\xC3\x84",
  15910. 'auml' => "\xC3\xA4",
  15911. 'Auml;' => "\xC3\x84",
  15912. 'auml;' => "\xC3\xA4",
  15913. 'bdquo;' => "\xE2\x80\x9E",
  15914. 'Beta;' => "\xCE\x92",
  15915. 'beta;' => "\xCE\xB2",
  15916. 'brvbar' => "\xC2\xA6",
  15917. 'brvbar;' => "\xC2\xA6",
  15918. 'bull;' => "\xE2\x80\xA2",
  15919. 'cap;' => "\xE2\x88\xA9",
  15920. 'Ccedil' => "\xC3\x87",
  15921. 'ccedil' => "\xC3\xA7",
  15922. 'Ccedil;' => "\xC3\x87",
  15923. 'ccedil;' => "\xC3\xA7",
  15924. 'cedil' => "\xC2\xB8",
  15925. 'cedil;' => "\xC2\xB8",
  15926. 'cent' => "\xC2\xA2",
  15927. 'cent;' => "\xC2\xA2",
  15928. 'Chi;' => "\xCE\xA7",
  15929. 'chi;' => "\xCF\x87",
  15930. 'circ;' => "\xCB\x86",
  15931. 'clubs;' => "\xE2\x99\xA3",
  15932. 'cong;' => "\xE2\x89\x85",
  15933. 'COPY' => "\xC2\xA9",
  15934. 'copy' => "\xC2\xA9",
  15935. 'COPY;' => "\xC2\xA9",
  15936. 'copy;' => "\xC2\xA9",
  15937. 'crarr;' => "\xE2\x86\xB5",
  15938. 'cup;' => "\xE2\x88\xAA",
  15939. 'curren' => "\xC2\xA4",
  15940. 'curren;' => "\xC2\xA4",
  15941. 'Dagger;' => "\xE2\x80\xA1",
  15942. 'dagger;' => "\xE2\x80\xA0",
  15943. 'dArr;' => "\xE2\x87\x93",
  15944. 'darr;' => "\xE2\x86\x93",
  15945. 'deg' => "\xC2\xB0",
  15946. 'deg;' => "\xC2\xB0",
  15947. 'Delta;' => "\xCE\x94",
  15948. 'delta;' => "\xCE\xB4",
  15949. 'diams;' => "\xE2\x99\xA6",
  15950. 'divide' => "\xC3\xB7",
  15951. 'divide;' => "\xC3\xB7",
  15952. 'Eacute' => "\xC3\x89",
  15953. 'eacute' => "\xC3\xA9",
  15954. 'Eacute;' => "\xC3\x89",
  15955. 'eacute;' => "\xC3\xA9",
  15956. 'Ecirc' => "\xC3\x8A",
  15957. 'ecirc' => "\xC3\xAA",
  15958. 'Ecirc;' => "\xC3\x8A",
  15959. 'ecirc;' => "\xC3\xAA",
  15960. 'Egrave' => "\xC3\x88",
  15961. 'egrave' => "\xC3\xA8",
  15962. 'Egrave;' => "\xC3\x88",
  15963. 'egrave;' => "\xC3\xA8",
  15964. 'empty;' => "\xE2\x88\x85",
  15965. 'emsp;' => "\xE2\x80\x83",
  15966. 'ensp;' => "\xE2\x80\x82",
  15967. 'Epsilon;' => "\xCE\x95",
  15968. 'epsilon;' => "\xCE\xB5",
  15969. 'equiv;' => "\xE2\x89\xA1",
  15970. 'Eta;' => "\xCE\x97",
  15971. 'eta;' => "\xCE\xB7",
  15972. 'ETH' => "\xC3\x90",
  15973. 'eth' => "\xC3\xB0",
  15974. 'ETH;' => "\xC3\x90",
  15975. 'eth;' => "\xC3\xB0",
  15976. 'Euml' => "\xC3\x8B",
  15977. 'euml' => "\xC3\xAB",
  15978. 'Euml;' => "\xC3\x8B",
  15979. 'euml;' => "\xC3\xAB",
  15980. 'euro;' => "\xE2\x82\xAC",
  15981. 'exist;' => "\xE2\x88\x83",
  15982. 'fnof;' => "\xC6\x92",
  15983. 'forall;' => "\xE2\x88\x80",
  15984. 'frac12' => "\xC2\xBD",
  15985. 'frac12;' => "\xC2\xBD",
  15986. 'frac14' => "\xC2\xBC",
  15987. 'frac14;' => "\xC2\xBC",
  15988. 'frac34' => "\xC2\xBE",
  15989. 'frac34;' => "\xC2\xBE",
  15990. 'frasl;' => "\xE2\x81\x84",
  15991. 'Gamma;' => "\xCE\x93",
  15992. 'gamma;' => "\xCE\xB3",
  15993. 'ge;' => "\xE2\x89\xA5",
  15994. 'GT' => "\x3E",
  15995. 'gt' => "\x3E",
  15996. 'GT;' => "\x3E",
  15997. 'gt;' => "\x3E",
  15998. 'hArr;' => "\xE2\x87\x94",
  15999. 'harr;' => "\xE2\x86\x94",
  16000. 'hearts;' => "\xE2\x99\xA5",
  16001. 'hellip;' => "\xE2\x80\xA6",
  16002. 'Iacute' => "\xC3\x8D",
  16003. 'iacute' => "\xC3\xAD",
  16004. 'Iacute;' => "\xC3\x8D",
  16005. 'iacute;' => "\xC3\xAD",
  16006. 'Icirc' => "\xC3\x8E",
  16007. 'icirc' => "\xC3\xAE",
  16008. 'Icirc;' => "\xC3\x8E",
  16009. 'icirc;' => "\xC3\xAE",
  16010. 'iexcl' => "\xC2\xA1",
  16011. 'iexcl;' => "\xC2\xA1",
  16012. 'Igrave' => "\xC3\x8C",
  16013. 'igrave' => "\xC3\xAC",
  16014. 'Igrave;' => "\xC3\x8C",
  16015. 'igrave;' => "\xC3\xAC",
  16016. 'image;' => "\xE2\x84\x91",
  16017. 'infin;' => "\xE2\x88\x9E",
  16018. 'int;' => "\xE2\x88\xAB",
  16019. 'Iota;' => "\xCE\x99",
  16020. 'iota;' => "\xCE\xB9",
  16021. 'iquest' => "\xC2\xBF",
  16022. 'iquest;' => "\xC2\xBF",
  16023. 'isin;' => "\xE2\x88\x88",
  16024. 'Iuml' => "\xC3\x8F",
  16025. 'iuml' => "\xC3\xAF",
  16026. 'Iuml;' => "\xC3\x8F",
  16027. 'iuml;' => "\xC3\xAF",
  16028. 'Kappa;' => "\xCE\x9A",
  16029. 'kappa;' => "\xCE\xBA",
  16030. 'Lambda;' => "\xCE\x9B",
  16031. 'lambda;' => "\xCE\xBB",
  16032. 'lang;' => "\xE3\x80\x88",
  16033. 'laquo' => "\xC2\xAB",
  16034. 'laquo;' => "\xC2\xAB",
  16035. 'lArr;' => "\xE2\x87\x90",
  16036. 'larr;' => "\xE2\x86\x90",
  16037. 'lceil;' => "\xE2\x8C\x88",
  16038. 'ldquo;' => "\xE2\x80\x9C",
  16039. 'le;' => "\xE2\x89\xA4",
  16040. 'lfloor;' => "\xE2\x8C\x8A",
  16041. 'lowast;' => "\xE2\x88\x97",
  16042. 'loz;' => "\xE2\x97\x8A",
  16043. 'lrm;' => "\xE2\x80\x8E",
  16044. 'lsaquo;' => "\xE2\x80\xB9",
  16045. 'lsquo;' => "\xE2\x80\x98",
  16046. 'LT' => "\x3C",
  16047. 'lt' => "\x3C",
  16048. 'LT;' => "\x3C",
  16049. 'lt;' => "\x3C",
  16050. 'macr' => "\xC2\xAF",
  16051. 'macr;' => "\xC2\xAF",
  16052. 'mdash;' => "\xE2\x80\x94",
  16053. 'micro' => "\xC2\xB5",
  16054. 'micro;' => "\xC2\xB5",
  16055. 'middot' => "\xC2\xB7",
  16056. 'middot;' => "\xC2\xB7",
  16057. 'minus;' => "\xE2\x88\x92",
  16058. 'Mu;' => "\xCE\x9C",
  16059. 'mu;' => "\xCE\xBC",
  16060. 'nabla;' => "\xE2\x88\x87",
  16061. 'nbsp' => "\xC2\xA0",
  16062. 'nbsp;' => "\xC2\xA0",
  16063. 'ndash;' => "\xE2\x80\x93",
  16064. 'ne;' => "\xE2\x89\xA0",
  16065. 'ni;' => "\xE2\x88\x8B",
  16066. 'not' => "\xC2\xAC",
  16067. 'not;' => "\xC2\xAC",
  16068. 'notin;' => "\xE2\x88\x89",
  16069. 'nsub;' => "\xE2\x8A\x84",
  16070. 'Ntilde' => "\xC3\x91",
  16071. 'ntilde' => "\xC3\xB1",
  16072. 'Ntilde;' => "\xC3\x91",
  16073. 'ntilde;' => "\xC3\xB1",
  16074. 'Nu;' => "\xCE\x9D",
  16075. 'nu;' => "\xCE\xBD",
  16076. 'Oacute' => "\xC3\x93",
  16077. 'oacute' => "\xC3\xB3",
  16078. 'Oacute;' => "\xC3\x93",
  16079. 'oacute;' => "\xC3\xB3",
  16080. 'Ocirc' => "\xC3\x94",
  16081. 'ocirc' => "\xC3\xB4",
  16082. 'Ocirc;' => "\xC3\x94",
  16083. 'ocirc;' => "\xC3\xB4",
  16084. 'OElig;' => "\xC5\x92",
  16085. 'oelig;' => "\xC5\x93",
  16086. 'Ograve' => "\xC3\x92",
  16087. 'ograve' => "\xC3\xB2",
  16088. 'Ograve;' => "\xC3\x92",
  16089. 'ograve;' => "\xC3\xB2",
  16090. 'oline;' => "\xE2\x80\xBE",
  16091. 'Omega;' => "\xCE\xA9",
  16092. 'omega;' => "\xCF\x89",
  16093. 'Omicron;' => "\xCE\x9F",
  16094. 'omicron;' => "\xCE\xBF",
  16095. 'oplus;' => "\xE2\x8A\x95",
  16096. 'or;' => "\xE2\x88\xA8",
  16097. 'ordf' => "\xC2\xAA",
  16098. 'ordf;' => "\xC2\xAA",
  16099. 'ordm' => "\xC2\xBA",
  16100. 'ordm;' => "\xC2\xBA",
  16101. 'Oslash' => "\xC3\x98",
  16102. 'oslash' => "\xC3\xB8",
  16103. 'Oslash;' => "\xC3\x98",
  16104. 'oslash;' => "\xC3\xB8",
  16105. 'Otilde' => "\xC3\x95",
  16106. 'otilde' => "\xC3\xB5",
  16107. 'Otilde;' => "\xC3\x95",
  16108. 'otilde;' => "\xC3\xB5",
  16109. 'otimes;' => "\xE2\x8A\x97",
  16110. 'Ouml' => "\xC3\x96",
  16111. 'ouml' => "\xC3\xB6",
  16112. 'Ouml;' => "\xC3\x96",
  16113. 'ouml;' => "\xC3\xB6",
  16114. 'para' => "\xC2\xB6",
  16115. 'para;' => "\xC2\xB6",
  16116. 'part;' => "\xE2\x88\x82",
  16117. 'permil;' => "\xE2\x80\xB0",
  16118. 'perp;' => "\xE2\x8A\xA5",
  16119. 'Phi;' => "\xCE\xA6",
  16120. 'phi;' => "\xCF\x86",
  16121. 'Pi;' => "\xCE\xA0",
  16122. 'pi;' => "\xCF\x80",
  16123. 'piv;' => "\xCF\x96",
  16124. 'plusmn' => "\xC2\xB1",
  16125. 'plusmn;' => "\xC2\xB1",
  16126. 'pound' => "\xC2\xA3",
  16127. 'pound;' => "\xC2\xA3",
  16128. 'Prime;' => "\xE2\x80\xB3",
  16129. 'prime;' => "\xE2\x80\xB2",
  16130. 'prod;' => "\xE2\x88\x8F",
  16131. 'prop;' => "\xE2\x88\x9D",
  16132. 'Psi;' => "\xCE\xA8",
  16133. 'psi;' => "\xCF\x88",
  16134. 'QUOT' => "\x22",
  16135. 'quot' => "\x22",
  16136. 'QUOT;' => "\x22",
  16137. 'quot;' => "\x22",
  16138. 'radic;' => "\xE2\x88\x9A",
  16139. 'rang;' => "\xE3\x80\x89",
  16140. 'raquo' => "\xC2\xBB",
  16141. 'raquo;' => "\xC2\xBB",
  16142. 'rArr;' => "\xE2\x87\x92",
  16143. 'rarr;' => "\xE2\x86\x92",
  16144. 'rceil;' => "\xE2\x8C\x89",
  16145. 'rdquo;' => "\xE2\x80\x9D",
  16146. 'real;' => "\xE2\x84\x9C",
  16147. 'REG' => "\xC2\xAE",
  16148. 'reg' => "\xC2\xAE",
  16149. 'REG;' => "\xC2\xAE",
  16150. 'reg;' => "\xC2\xAE",
  16151. 'rfloor;' => "\xE2\x8C\x8B",
  16152. 'Rho;' => "\xCE\xA1",
  16153. 'rho;' => "\xCF\x81",
  16154. 'rlm;' => "\xE2\x80\x8F",
  16155. 'rsaquo;' => "\xE2\x80\xBA",
  16156. 'rsquo;' => "\xE2\x80\x99",
  16157. 'sbquo;' => "\xE2\x80\x9A",
  16158. 'Scaron;' => "\xC5\xA0",
  16159. 'scaron;' => "\xC5\xA1",
  16160. 'sdot;' => "\xE2\x8B\x85",
  16161. 'sect' => "\xC2\xA7",
  16162. 'sect;' => "\xC2\xA7",
  16163. 'shy' => "\xC2\xAD",
  16164. 'shy;' => "\xC2\xAD",
  16165. 'Sigma;' => "\xCE\xA3",
  16166. 'sigma;' => "\xCF\x83",
  16167. 'sigmaf;' => "\xCF\x82",
  16168. 'sim;' => "\xE2\x88\xBC",
  16169. 'spades;' => "\xE2\x99\xA0",
  16170. 'sub;' => "\xE2\x8A\x82",
  16171. 'sube;' => "\xE2\x8A\x86",
  16172. 'sum;' => "\xE2\x88\x91",
  16173. 'sup;' => "\xE2\x8A\x83",
  16174. 'sup1' => "\xC2\xB9",
  16175. 'sup1;' => "\xC2\xB9",
  16176. 'sup2' => "\xC2\xB2",
  16177. 'sup2;' => "\xC2\xB2",
  16178. 'sup3' => "\xC2\xB3",
  16179. 'sup3;' => "\xC2\xB3",
  16180. 'supe;' => "\xE2\x8A\x87",
  16181. 'szlig' => "\xC3\x9F",
  16182. 'szlig;' => "\xC3\x9F",
  16183. 'Tau;' => "\xCE\xA4",
  16184. 'tau;' => "\xCF\x84",
  16185. 'there4;' => "\xE2\x88\xB4",
  16186. 'Theta;' => "\xCE\x98",
  16187. 'theta;' => "\xCE\xB8",
  16188. 'thetasym;' => "\xCF\x91",
  16189. 'thinsp;' => "\xE2\x80\x89",
  16190. 'THORN' => "\xC3\x9E",
  16191. 'thorn' => "\xC3\xBE",
  16192. 'THORN;' => "\xC3\x9E",
  16193. 'thorn;' => "\xC3\xBE",
  16194. 'tilde;' => "\xCB\x9C",
  16195. 'times' => "\xC3\x97",
  16196. 'times;' => "\xC3\x97",
  16197. 'TRADE;' => "\xE2\x84\xA2",
  16198. 'trade;' => "\xE2\x84\xA2",
  16199. 'Uacute' => "\xC3\x9A",
  16200. 'uacute' => "\xC3\xBA",
  16201. 'Uacute;' => "\xC3\x9A",
  16202. 'uacute;' => "\xC3\xBA",
  16203. 'uArr;' => "\xE2\x87\x91",
  16204. 'uarr;' => "\xE2\x86\x91",
  16205. 'Ucirc' => "\xC3\x9B",
  16206. 'ucirc' => "\xC3\xBB",
  16207. 'Ucirc;' => "\xC3\x9B",
  16208. 'ucirc;' => "\xC3\xBB",
  16209. 'Ugrave' => "\xC3\x99",
  16210. 'ugrave' => "\xC3\xB9",
  16211. 'Ugrave;' => "\xC3\x99",
  16212. 'ugrave;' => "\xC3\xB9",
  16213. 'uml' => "\xC2\xA8",
  16214. 'uml;' => "\xC2\xA8",
  16215. 'upsih;' => "\xCF\x92",
  16216. 'Upsilon;' => "\xCE\xA5",
  16217. 'upsilon;' => "\xCF\x85",
  16218. 'Uuml' => "\xC3\x9C",
  16219. 'uuml' => "\xC3\xBC",
  16220. 'Uuml;' => "\xC3\x9C",
  16221. 'uuml;' => "\xC3\xBC",
  16222. 'weierp;' => "\xE2\x84\x98",
  16223. 'Xi;' => "\xCE\x9E",
  16224. 'xi;' => "\xCE\xBE",
  16225. 'Yacute' => "\xC3\x9D",
  16226. 'yacute' => "\xC3\xBD",
  16227. 'Yacute;' => "\xC3\x9D",
  16228. 'yacute;' => "\xC3\xBD",
  16229. 'yen' => "\xC2\xA5",
  16230. 'yen;' => "\xC2\xA5",
  16231. 'yuml' => "\xC3\xBF",
  16232. 'Yuml;' => "\xC5\xB8",
  16233. 'yuml;' => "\xC3\xBF",
  16234. 'Zeta;' => "\xCE\x96",
  16235. 'zeta;' => "\xCE\xB6",
  16236. 'zwj;' => "\xE2\x80\x8D",
  16237. 'zwnj;' => "\xE2\x80\x8C"
  16238. );
  16239. for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
  16240. {
  16241. $consumed = substr($this->consumed, 1);
  16242. if (isset($entities[$consumed]))
  16243. {
  16244. $match = $consumed;
  16245. }
  16246. }
  16247. if ($match !== null)
  16248. {
  16249. $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
  16250. $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
  16251. }
  16252. break;
  16253. }
  16254. }
  16255. }