PageRenderTime 123ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 1ms

/inc/app/news/lib/simplepie.php

https://github.com/lux/sitellite
PHP | 17595 lines | 13661 code | 795 blank | 3139 comment | 1080 complexity | eeb028a5a389ce541236cf806af6b6b3 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, GPL-3.0
  1. <?php
  2. /**
  3. * SimplePie
  4. *
  5. * A PHP-Based RSS and Atom Feed Framework.
  6. * Takes the hard work out of managing a complete RSS/Atom solution.
  7. *
  8. * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without modification, are
  12. * permitted provided that the following conditions are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright notice, this list of
  15. * conditions and the following disclaimer.
  16. *
  17. * * Redistributions in binary form must reproduce the above copyright notice, this list
  18. * of conditions and the following disclaimer in the documentation and/or other materials
  19. * provided with the distribution.
  20. *
  21. * * Neither the name of the SimplePie Team nor the names of its contributors may be used
  22. * to endorse or promote products derived from this software without specific prior
  23. * written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  26. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  27. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  28. * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  30. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  32. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. * @package SimplePie
  36. * @version 1.3
  37. * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  38. * @author Ryan Parman
  39. * @author Geoffrey Sneddon
  40. * @author Ryan McCue
  41. * @link http://simplepie.org/ SimplePie
  42. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  43. */
  44. /**
  45. * SimplePie Name
  46. */
  47. define('SIMPLEPIE_NAME', 'SimplePie');
  48. /**
  49. * SimplePie Version
  50. */
  51. define('SIMPLEPIE_VERSION', '1.3');
  52. /**
  53. * SimplePie Build
  54. * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
  55. */
  56. define('SIMPLEPIE_BUILD', '20120707113013');
  57. /**
  58. * SimplePie Website URL
  59. */
  60. define('SIMPLEPIE_URL', 'http://simplepie.org');
  61. /**
  62. * SimplePie Useragent
  63. * @see SimplePie::set_useragent()
  64. */
  65. define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
  66. /**
  67. * SimplePie Linkback
  68. */
  69. define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
  70. /**
  71. * No Autodiscovery
  72. * @see SimplePie::set_autodiscovery_level()
  73. */
  74. define('SIMPLEPIE_LOCATOR_NONE', 0);
  75. /**
  76. * Feed Link Element Autodiscovery
  77. * @see SimplePie::set_autodiscovery_level()
  78. */
  79. define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
  80. /**
  81. * Local Feed Extension Autodiscovery
  82. * @see SimplePie::set_autodiscovery_level()
  83. */
  84. define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
  85. /**
  86. * Local Feed Body Autodiscovery
  87. * @see SimplePie::set_autodiscovery_level()
  88. */
  89. define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
  90. /**
  91. * Remote Feed Extension Autodiscovery
  92. * @see SimplePie::set_autodiscovery_level()
  93. */
  94. define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
  95. /**
  96. * Remote Feed Body Autodiscovery
  97. * @see SimplePie::set_autodiscovery_level()
  98. */
  99. define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
  100. /**
  101. * All Feed Autodiscovery
  102. * @see SimplePie::set_autodiscovery_level()
  103. */
  104. define('SIMPLEPIE_LOCATOR_ALL', 31);
  105. /**
  106. * No known feed type
  107. */
  108. define('SIMPLEPIE_TYPE_NONE', 0);
  109. /**
  110. * RSS 0.90
  111. */
  112. define('SIMPLEPIE_TYPE_RSS_090', 1);
  113. /**
  114. * RSS 0.91 (Netscape)
  115. */
  116. define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
  117. /**
  118. * RSS 0.91 (Userland)
  119. */
  120. define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
  121. /**
  122. * RSS 0.91 (both Netscape and Userland)
  123. */
  124. define('SIMPLEPIE_TYPE_RSS_091', 6);
  125. /**
  126. * RSS 0.92
  127. */
  128. define('SIMPLEPIE_TYPE_RSS_092', 8);
  129. /**
  130. * RSS 0.93
  131. */
  132. define('SIMPLEPIE_TYPE_RSS_093', 16);
  133. /**
  134. * RSS 0.94
  135. */
  136. define('SIMPLEPIE_TYPE_RSS_094', 32);
  137. /**
  138. * RSS 1.0
  139. */
  140. define('SIMPLEPIE_TYPE_RSS_10', 64);
  141. /**
  142. * RSS 2.0
  143. */
  144. define('SIMPLEPIE_TYPE_RSS_20', 128);
  145. /**
  146. * RDF-based RSS
  147. */
  148. define('SIMPLEPIE_TYPE_RSS_RDF', 65);
  149. /**
  150. * Non-RDF-based RSS (truly intended as syndication format)
  151. */
  152. define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
  153. /**
  154. * All RSS
  155. */
  156. define('SIMPLEPIE_TYPE_RSS_ALL', 255);
  157. /**
  158. * Atom 0.3
  159. */
  160. define('SIMPLEPIE_TYPE_ATOM_03', 256);
  161. /**
  162. * Atom 1.0
  163. */
  164. define('SIMPLEPIE_TYPE_ATOM_10', 512);
  165. /**
  166. * All Atom
  167. */
  168. define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
  169. /**
  170. * All feed types
  171. */
  172. define('SIMPLEPIE_TYPE_ALL', 1023);
  173. /**
  174. * No construct
  175. */
  176. define('SIMPLEPIE_CONSTRUCT_NONE', 0);
  177. /**
  178. * Text construct
  179. */
  180. define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
  181. /**
  182. * HTML construct
  183. */
  184. define('SIMPLEPIE_CONSTRUCT_HTML', 2);
  185. /**
  186. * XHTML construct
  187. */
  188. define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
  189. /**
  190. * base64-encoded construct
  191. */
  192. define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
  193. /**
  194. * IRI construct
  195. */
  196. define('SIMPLEPIE_CONSTRUCT_IRI', 16);
  197. /**
  198. * A construct that might be HTML
  199. */
  200. define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
  201. /**
  202. * All constructs
  203. */
  204. define('SIMPLEPIE_CONSTRUCT_ALL', 63);
  205. /**
  206. * Don't change case
  207. */
  208. define('SIMPLEPIE_SAME_CASE', 1);
  209. /**
  210. * Change to lowercase
  211. */
  212. define('SIMPLEPIE_LOWERCASE', 2);
  213. /**
  214. * Change to uppercase
  215. */
  216. define('SIMPLEPIE_UPPERCASE', 4);
  217. /**
  218. * PCRE for HTML attributes
  219. */
  220. 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]*');
  221. /**
  222. * PCRE for XML attributes
  223. */
  224. define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
  225. /**
  226. * XML Namespace
  227. */
  228. define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
  229. /**
  230. * Atom 1.0 Namespace
  231. */
  232. define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
  233. /**
  234. * Atom 0.3 Namespace
  235. */
  236. define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
  237. /**
  238. * RDF Namespace
  239. */
  240. define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
  241. /**
  242. * RSS 0.90 Namespace
  243. */
  244. define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
  245. /**
  246. * RSS 1.0 Namespace
  247. */
  248. define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
  249. /**
  250. * RSS 1.0 Content Module Namespace
  251. */
  252. define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
  253. /**
  254. * RSS 2.0 Namespace
  255. * (Stupid, I know, but I'm certain it will confuse people less with support.)
  256. */
  257. define('SIMPLEPIE_NAMESPACE_RSS_20', '');
  258. /**
  259. * DC 1.0 Namespace
  260. */
  261. define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
  262. /**
  263. * DC 1.1 Namespace
  264. */
  265. define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
  266. /**
  267. * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
  268. */
  269. define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
  270. /**
  271. * GeoRSS Namespace
  272. */
  273. define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
  274. /**
  275. * Media RSS Namespace
  276. */
  277. define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
  278. /**
  279. * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
  280. */
  281. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
  282. /**
  283. * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
  284. */
  285. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
  286. /**
  287. * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
  288. */
  289. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
  290. /**
  291. * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
  292. */
  293. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
  294. /**
  295. * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
  296. */
  297. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
  298. /**
  299. * iTunes RSS Namespace
  300. */
  301. define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
  302. /**
  303. * XHTML Namespace
  304. */
  305. define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
  306. /**
  307. * IANA Link Relations Registry
  308. */
  309. define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
  310. /**
  311. * No file source
  312. */
  313. define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
  314. /**
  315. * Remote file source
  316. */
  317. define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
  318. /**
  319. * Local file source
  320. */
  321. define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
  322. /**
  323. * fsockopen() file source
  324. */
  325. define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
  326. /**
  327. * cURL file source
  328. */
  329. define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
  330. /**
  331. * file_get_contents() file source
  332. */
  333. define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
  334. /**
  335. * SimplePie
  336. *
  337. * @package SimplePie
  338. * @subpackage API
  339. */
  340. class SimplePie
  341. {
  342. /**
  343. * @var array Raw data
  344. * @access private
  345. */
  346. public $data = array();
  347. /**
  348. * @var mixed Error string
  349. * @access private
  350. */
  351. public $error;
  352. /**
  353. * @var object Instance of SimplePie_Sanitize (or other class)
  354. * @see SimplePie::set_sanitize_class()
  355. * @access private
  356. */
  357. public $sanitize;
  358. /**
  359. * @var string SimplePie Useragent
  360. * @see SimplePie::set_useragent()
  361. * @access private
  362. */
  363. public $useragent = SIMPLEPIE_USERAGENT;
  364. /**
  365. * @var string Feed URL
  366. * @see SimplePie::set_feed_url()
  367. * @access private
  368. */
  369. public $feed_url;
  370. /**
  371. * @var object Instance of SimplePie_File to use as a feed
  372. * @see SimplePie::set_file()
  373. * @access private
  374. */
  375. public $file;
  376. /**
  377. * @var string Raw feed data
  378. * @see SimplePie::set_raw_data()
  379. * @access private
  380. */
  381. public $raw_data;
  382. /**
  383. * @var int Timeout for fetching remote files
  384. * @see SimplePie::set_timeout()
  385. * @access private
  386. */
  387. public $timeout = 10;
  388. /**
  389. * @var bool Forces fsockopen() to be used for remote files instead
  390. * of cURL, even if a new enough version is installed
  391. * @see SimplePie::force_fsockopen()
  392. * @access private
  393. */
  394. public $force_fsockopen = false;
  395. /**
  396. * @var bool Force the given data/URL to be treated as a feed no matter what
  397. * it appears like
  398. * @see SimplePie::force_feed()
  399. * @access private
  400. */
  401. public $force_feed = false;
  402. /**
  403. * @var bool Enable/Disable Caching
  404. * @see SimplePie::enable_cache()
  405. * @access private
  406. */
  407. public $cache = true;
  408. /**
  409. * @var int Cache duration (in seconds)
  410. * @see SimplePie::set_cache_duration()
  411. * @access private
  412. */
  413. public $cache_duration = 3600;
  414. /**
  415. * @var int Auto-discovery cache duration (in seconds)
  416. * @see SimplePie::set_autodiscovery_cache_duration()
  417. * @access private
  418. */
  419. public $autodiscovery_cache_duration = 604800; // 7 Days.
  420. /**
  421. * @var string Cache location (relative to executing script)
  422. * @see SimplePie::set_cache_location()
  423. * @access private
  424. */
  425. public $cache_location = './cache';
  426. /**
  427. * @var string Function that creates the cache filename
  428. * @see SimplePie::set_cache_name_function()
  429. * @access private
  430. */
  431. public $cache_name_function = 'md5';
  432. /**
  433. * @var bool Reorder feed by date descending
  434. * @see SimplePie::enable_order_by_date()
  435. * @access private
  436. */
  437. public $order_by_date = true;
  438. /**
  439. * @var mixed Force input encoding to be set to the follow value
  440. * (false, or anything type-cast to false, disables this feature)
  441. * @see SimplePie::set_input_encoding()
  442. * @access private
  443. */
  444. public $input_encoding = false;
  445. /**
  446. * @var int Feed Autodiscovery Level
  447. * @see SimplePie::set_autodiscovery_level()
  448. * @access private
  449. */
  450. public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
  451. /**
  452. * Class registry object
  453. *
  454. * @var SimplePie_Registry
  455. */
  456. public $registry;
  457. /**
  458. * @var int Maximum number of feeds to check with autodiscovery
  459. * @see SimplePie::set_max_checked_feeds()
  460. * @access private
  461. */
  462. public $max_checked_feeds = 10;
  463. /**
  464. * @var array All the feeds found during the autodiscovery process
  465. * @see SimplePie::get_all_discovered_feeds()
  466. * @access private
  467. */
  468. public $all_discovered_feeds = array();
  469. /**
  470. * @var string Web-accessible path to the handler_image.php file.
  471. * @see SimplePie::set_image_handler()
  472. * @access private
  473. */
  474. public $image_handler = '';
  475. /**
  476. * @var array Stores the URLs when multiple feeds are being initialized.
  477. * @see SimplePie::set_feed_url()
  478. * @access private
  479. */
  480. public $multifeed_url = array();
  481. /**
  482. * @var array Stores SimplePie objects when multiple feeds initialized.
  483. * @access private
  484. */
  485. public $multifeed_objects = array();
  486. /**
  487. * @var array Stores the get_object_vars() array for use with multifeeds.
  488. * @see SimplePie::set_feed_url()
  489. * @access private
  490. */
  491. public $config_settings = null;
  492. /**
  493. * @var integer Stores the number of items to return per-feed with multifeeds.
  494. * @see SimplePie::set_item_limit()
  495. * @access private
  496. */
  497. public $item_limit = 0;
  498. /**
  499. * @var array Stores the default attributes to be stripped by strip_attributes().
  500. * @see SimplePie::strip_attributes()
  501. * @access private
  502. */
  503. public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
  504. /**
  505. * @var array Stores the default tags to be stripped by strip_htmltags().
  506. * @see SimplePie::strip_htmltags()
  507. * @access private
  508. */
  509. public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
  510. /**
  511. * The SimplePie class contains feed level data and options
  512. *
  513. * To use SimplePie, create the SimplePie object with no parameters. You can
  514. * then set configuration options using the provided methods. After setting
  515. * them, you must initialise the feed using $feed->init(). At that point the
  516. * object's methods and properties will be available to you.
  517. *
  518. * Previously, it was possible to pass in the feed URL along with cache
  519. * options directly into the constructor. This has been removed as of 1.3 as
  520. * it caused a lot of confusion.
  521. *
  522. * @since 1.0 Preview Release
  523. */
  524. public function __construct()
  525. {
  526. if (version_compare(PHP_VERSION, '5.2', '<'))
  527. {
  528. trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
  529. die();
  530. }
  531. // Other objects, instances created here so we can set options on them
  532. $this->sanitize = new SimplePie_Sanitize();
  533. $this->registry = new SimplePie_Registry();
  534. if (func_num_args() > 0)
  535. {
  536. trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.');
  537. }
  538. }
  539. /**
  540. * Used for converting object to a string
  541. */
  542. public function __toString()
  543. {
  544. return md5(serialize($this->data));
  545. }
  546. /**
  547. * Remove items that link back to this before destroying this object
  548. */
  549. public function __destruct()
  550. {
  551. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  552. {
  553. if (!empty($this->data['items']))
  554. {
  555. foreach ($this->data['items'] as $item)
  556. {
  557. $item->__destruct();
  558. }
  559. unset($item, $this->data['items']);
  560. }
  561. if (!empty($this->data['ordered_items']))
  562. {
  563. foreach ($this->data['ordered_items'] as $item)
  564. {
  565. $item->__destruct();
  566. }
  567. unset($item, $this->data['ordered_items']);
  568. }
  569. }
  570. }
  571. /**
  572. * Force the given data/URL to be treated as a feed
  573. *
  574. * This tells SimplePie to ignore the content-type provided by the server.
  575. * Be careful when using this option, as it will also disable autodiscovery.
  576. *
  577. * @since 1.1
  578. * @param bool $enable Force the given data/URL to be treated as a feed
  579. */
  580. public function force_feed($enable = false)
  581. {
  582. $this->force_feed = (bool) $enable;
  583. }
  584. /**
  585. * Set the URL of the feed you want to parse
  586. *
  587. * This allows you to enter the URL of the feed you want to parse, or the
  588. * website you want to try to use auto-discovery on. This takes priority
  589. * over any set raw data.
  590. *
  591. * You can set multiple feeds to mash together by passing an array instead
  592. * of a string for the $url. Remember that with each additional feed comes
  593. * additional processing and resources.
  594. *
  595. * @since 1.0 Preview Release
  596. * @see set_raw_data()
  597. * @param string|array $url This is the URL (or array of URLs) that you want to parse.
  598. */
  599. public function set_feed_url($url)
  600. {
  601. $this->multifeed_url = array();
  602. if (is_array($url))
  603. {
  604. foreach ($url as $value)
  605. {
  606. $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
  607. }
  608. }
  609. else
  610. {
  611. $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
  612. }
  613. }
  614. /**
  615. * Set an instance of {@see SimplePie_File} to use as a feed
  616. *
  617. * @param SimplePie_File &$file
  618. * @return bool True on success, false on failure
  619. */
  620. public function set_file(&$file)
  621. {
  622. if ($file instanceof SimplePie_File)
  623. {
  624. $this->feed_url = $file->url;
  625. $this->file =& $file;
  626. return true;
  627. }
  628. return false;
  629. }
  630. /**
  631. * Set the raw XML data to parse
  632. *
  633. * Allows you to use a string of RSS/Atom data instead of a remote feed.
  634. *
  635. * If you have a feed available as a string in PHP, you can tell SimplePie
  636. * to parse that data string instead of a remote feed. Any set feed URL
  637. * takes precedence.
  638. *
  639. * @since 1.0 Beta 3
  640. * @param string $data RSS or Atom data as a string.
  641. * @see set_feed_url()
  642. */
  643. public function set_raw_data($data)
  644. {
  645. $this->raw_data = $data;
  646. }
  647. /**
  648. * Set the the default timeout for fetching remote feeds
  649. *
  650. * This allows you to change the maximum time the feed's server to respond
  651. * and send the feed back.
  652. *
  653. * @since 1.0 Beta 3
  654. * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
  655. */
  656. public function set_timeout($timeout = 10)
  657. {
  658. $this->timeout = (int) $timeout;
  659. }
  660. /**
  661. * Force SimplePie to use fsockopen() instead of cURL
  662. *
  663. * @since 1.0 Beta 3
  664. * @param bool $enable Force fsockopen() to be used
  665. */
  666. public function force_fsockopen($enable = false)
  667. {
  668. $this->force_fsockopen = (bool) $enable;
  669. }
  670. /**
  671. * Enable/disable caching in SimplePie.
  672. *
  673. * This option allows you to disable caching all-together in SimplePie.
  674. * However, disabling the cache can lead to longer load times.
  675. *
  676. * @since 1.0 Preview Release
  677. * @param bool $enable Enable caching
  678. */
  679. public function enable_cache($enable = true)
  680. {
  681. $this->cache = (bool) $enable;
  682. }
  683. /**
  684. * Set the length of time (in seconds) that the contents of a feed will be
  685. * cached
  686. *
  687. * @param int $seconds The feed content cache duration
  688. */
  689. public function set_cache_duration($seconds = 3600)
  690. {
  691. $this->cache_duration = (int) $seconds;
  692. }
  693. /**
  694. * Set the length of time (in seconds) that the autodiscovered feed URL will
  695. * be cached
  696. *
  697. * @param int $seconds The autodiscovered feed URL cache duration.
  698. */
  699. public function set_autodiscovery_cache_duration($seconds = 604800)
  700. {
  701. $this->autodiscovery_cache_duration = (int) $seconds;
  702. }
  703. /**
  704. * Set the file system location where the cached files should be stored
  705. *
  706. * @param string $location The file system location.
  707. */
  708. public function set_cache_location($location = './cache')
  709. {
  710. $this->cache_location = (string) $location;
  711. }
  712. /**
  713. * Set whether feed items should be sorted into reverse chronological order
  714. *
  715. * @param bool $enable Sort as reverse chronological order.
  716. */
  717. public function enable_order_by_date($enable = true)
  718. {
  719. $this->order_by_date = (bool) $enable;
  720. }
  721. /**
  722. * Set the character encoding used to parse the feed
  723. *
  724. * This overrides the encoding reported by the feed, however it will fall
  725. * back to the normal encoding detection if the override fails
  726. *
  727. * @param string $encoding Character encoding
  728. */
  729. public function set_input_encoding($encoding = false)
  730. {
  731. if ($encoding)
  732. {
  733. $this->input_encoding = (string) $encoding;
  734. }
  735. else
  736. {
  737. $this->input_encoding = false;
  738. }
  739. }
  740. /**
  741. * Set how much feed autodiscovery to do
  742. *
  743. * @see SIMPLEPIE_LOCATOR_NONE
  744. * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
  745. * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
  746. * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
  747. * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
  748. * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
  749. * @see SIMPLEPIE_LOCATOR_ALL
  750. * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
  751. */
  752. public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
  753. {
  754. $this->autodiscovery = (int) $level;
  755. }
  756. /**
  757. * Get the class registry
  758. *
  759. * Use this to override SimplePie's default classes
  760. * @see SimplePie_Registry
  761. * @return SimplePie_Registry
  762. */
  763. public function &get_registry()
  764. {
  765. return $this->registry;
  766. }
  767. /**#@+
  768. * Useful when you are overloading or extending SimplePie's default classes.
  769. *
  770. * @deprecated Use {@see get_registry()} instead
  771. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  772. * @param string $class Name of custom class
  773. * @return boolean True on success, false otherwise
  774. */
  775. /**
  776. * Set which class SimplePie uses for caching
  777. */
  778. public function set_cache_class($class = 'SimplePie_Cache')
  779. {
  780. return $this->registry->register('Cache', $class, true);
  781. }
  782. /**
  783. * Set which class SimplePie uses for auto-discovery
  784. */
  785. public function set_locator_class($class = 'SimplePie_Locator')
  786. {
  787. return $this->registry->register('Locator', $class, true);
  788. }
  789. /**
  790. * Set which class SimplePie uses for XML parsing
  791. */
  792. public function set_parser_class($class = 'SimplePie_Parser')
  793. {
  794. return $this->registry->register('Parser', $class, true);
  795. }
  796. /**
  797. * Set which class SimplePie uses for remote file fetching
  798. */
  799. public function set_file_class($class = 'SimplePie_File')
  800. {
  801. return $this->registry->register('File', $class, true);
  802. }
  803. /**
  804. * Set which class SimplePie uses for data sanitization
  805. */
  806. public function set_sanitize_class($class = 'SimplePie_Sanitize')
  807. {
  808. return $this->registry->register('Sanitize', $class, true);
  809. }
  810. /**
  811. * Set which class SimplePie uses for handling feed items
  812. */
  813. public function set_item_class($class = 'SimplePie_Item')
  814. {
  815. return $this->registry->register('Item', $class, true);
  816. }
  817. /**
  818. * Set which class SimplePie uses for handling author data
  819. */
  820. public function set_author_class($class = 'SimplePie_Author')
  821. {
  822. return $this->registry->register('Author', $class, true);
  823. }
  824. /**
  825. * Set which class SimplePie uses for handling category data
  826. */
  827. public function set_category_class($class = 'SimplePie_Category')
  828. {
  829. return $this->registry->register('Category', $class, true);
  830. }
  831. /**
  832. * Set which class SimplePie uses for feed enclosures
  833. */
  834. public function set_enclosure_class($class = 'SimplePie_Enclosure')
  835. {
  836. return $this->registry->register('Enclosure', $class, true);
  837. }
  838. /**
  839. * Set which class SimplePie uses for `<media:text>` captions
  840. */
  841. public function set_caption_class($class = 'SimplePie_Caption')
  842. {
  843. return $this->registry->register('Caption', $class, true);
  844. }
  845. /**
  846. * Set which class SimplePie uses for `<media:copyright>`
  847. */
  848. public function set_copyright_class($class = 'SimplePie_Copyright')
  849. {
  850. return $this->registry->register('Copyright', $class, true);
  851. }
  852. /**
  853. * Set which class SimplePie uses for `<media:credit>`
  854. */
  855. public function set_credit_class($class = 'SimplePie_Credit')
  856. {
  857. return $this->registry->register('Credit', $class, true);
  858. }
  859. /**
  860. * Set which class SimplePie uses for `<media:rating>`
  861. */
  862. public function set_rating_class($class = 'SimplePie_Rating')
  863. {
  864. return $this->registry->register('Rating', $class, true);
  865. }
  866. /**
  867. * Set which class SimplePie uses for `<media:restriction>`
  868. */
  869. public function set_restriction_class($class = 'SimplePie_Restriction')
  870. {
  871. return $this->registry->register('Restriction', $class, true);
  872. }
  873. /**
  874. * Set which class SimplePie uses for content-type sniffing
  875. */
  876. public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
  877. {
  878. return $this->registry->register('Content_Type_Sniffer', $class, true);
  879. }
  880. /**
  881. * Set which class SimplePie uses item sources
  882. */
  883. public function set_source_class($class = 'SimplePie_Source')
  884. {
  885. return $this->registry->register('Source', $class, true);
  886. }
  887. /**#@-*/
  888. /**
  889. * Set the user agent string
  890. *
  891. * @param string $ua New user agent string.
  892. */
  893. public function set_useragent($ua = SIMPLEPIE_USERAGENT)
  894. {
  895. $this->useragent = (string) $ua;
  896. }
  897. /**
  898. * Set callback function to create cache filename with
  899. *
  900. * @param mixed $function Callback function
  901. */
  902. public function set_cache_name_function($function = 'md5')
  903. {
  904. if (is_callable($function))
  905. {
  906. $this->cache_name_function = $function;
  907. }
  908. }
  909. /**
  910. * Set options to make SP as fast as possible
  911. *
  912. * Forgoes a substantial amount of data sanitization in favor of speed. This
  913. * turns SimplePie into a dumb parser of feeds.
  914. *
  915. * @param bool $set Whether to set them or not
  916. */
  917. public function set_stupidly_fast($set = false)
  918. {
  919. if ($set)
  920. {
  921. $this->enable_order_by_date(false);
  922. $this->remove_div(false);
  923. $this->strip_comments(false);
  924. $this->strip_htmltags(false);
  925. $this->strip_attributes(false);
  926. $this->set_image_handler(false);
  927. }
  928. }
  929. /**
  930. * Set maximum number of feeds to check with autodiscovery
  931. *
  932. * @param int $max Maximum number of feeds to check
  933. */
  934. public function set_max_checked_feeds($max = 10)
  935. {
  936. $this->max_checked_feeds = (int) $max;
  937. }
  938. public function remove_div($enable = true)
  939. {
  940. $this->sanitize->remove_div($enable);
  941. }
  942. public function strip_htmltags($tags = '', $encode = null)
  943. {
  944. if ($tags === '')
  945. {
  946. $tags = $this->strip_htmltags;
  947. }
  948. $this->sanitize->strip_htmltags($tags);
  949. if ($encode !== null)
  950. {
  951. $this->sanitize->encode_instead_of_strip($tags);
  952. }
  953. }
  954. public function encode_instead_of_strip($enable = true)
  955. {
  956. $this->sanitize->encode_instead_of_strip($enable);
  957. }
  958. public function strip_attributes($attribs = '')
  959. {
  960. if ($attribs === '')
  961. {
  962. $attribs = $this->strip_attributes;
  963. }
  964. $this->sanitize->strip_attributes($attribs);
  965. }
  966. /**
  967. * Set the output encoding
  968. *
  969. * Allows you to override SimplePie's output to match that of your webpage.
  970. * This is useful for times when your webpages are not being served as
  971. * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
  972. * is similar to {@see set_input_encoding()}.
  973. *
  974. * It should be noted, however, that not all character encodings can support
  975. * all characters. If your page is being served as ISO-8859-1 and you try
  976. * to display a Japanese feed, you'll likely see garbled characters.
  977. * Because of this, it is highly recommended to ensure that your webpages
  978. * are served as UTF-8.
  979. *
  980. * The number of supported character encodings depends on whether your web
  981. * host supports {@link http://php.net/mbstring mbstring},
  982. * {@link http://php.net/iconv iconv}, or both. See
  983. * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
  984. * more information.
  985. *
  986. * @param string $encoding
  987. */
  988. public function set_output_encoding($encoding = 'UTF-8')
  989. {
  990. $this->sanitize->set_output_encoding($encoding);
  991. }
  992. public function strip_comments($strip = false)
  993. {
  994. $this->sanitize->strip_comments($strip);
  995. }
  996. /**
  997. * Set element/attribute key/value pairs of HTML attributes
  998. * containing URLs that need to be resolved relative to the feed
  999. *
  1000. * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
  1001. * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
  1002. * |q|@cite
  1003. *
  1004. * @since 1.0
  1005. * @param array|null $element_attribute Element/attribute key/value pairs, null for default
  1006. */
  1007. public function set_url_replacements($element_attribute = null)
  1008. {
  1009. $this->sanitize->set_url_replacements($element_attribute);
  1010. }
  1011. /**
  1012. * Set the handler to enable the display of cached images.
  1013. *
  1014. * @param str $page Web-accessible path to the handler_image.php file.
  1015. * @param str $qs The query string that the value should be passed to.
  1016. */
  1017. public function set_image_handler($page = false, $qs = 'i')
  1018. {
  1019. if ($page !== false)
  1020. {
  1021. $this->sanitize->set_image_handler($page . '?' . $qs . '=');
  1022. }
  1023. else
  1024. {
  1025. $this->image_handler = '';
  1026. }
  1027. }
  1028. /**
  1029. * Set the limit for items returned per-feed with multifeeds
  1030. *
  1031. * @param integer $limit The maximum number of items to return.
  1032. */
  1033. public function set_item_limit($limit = 0)
  1034. {
  1035. $this->item_limit = (int) $limit;
  1036. }
  1037. /**
  1038. * Initialize the feed object
  1039. *
  1040. * This is what makes everything happen. Period. This is where all of the
  1041. * configuration options get processed, feeds are fetched, cached, and
  1042. * parsed, and all of that other good stuff.
  1043. *
  1044. * @return boolean True if successful, false otherwise
  1045. */
  1046. public function init()
  1047. {
  1048. // Check absolute bare minimum requirements.
  1049. if (!extension_loaded('xml') || !extension_loaded('pcre'))
  1050. {
  1051. return false;
  1052. }
  1053. // 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.
  1054. elseif (!extension_loaded('xmlreader'))
  1055. {
  1056. static $xml_is_sane = null;
  1057. if ($xml_is_sane === null)
  1058. {
  1059. $parser_check = xml_parser_create();
  1060. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  1061. xml_parser_free($parser_check);
  1062. $xml_is_sane = isset($values[0]['value']);
  1063. }
  1064. if (!$xml_is_sane)
  1065. {
  1066. return false;
  1067. }
  1068. }
  1069. if (method_exists($this->sanitize, 'set_registry'))
  1070. {
  1071. $this->sanitize->set_registry($this->registry);
  1072. }
  1073. // Pass whatever was set with config options over to the sanitizer.
  1074. // Pass the classes in for legacy support; new classes should use the registry instead
  1075. $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
  1076. $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
  1077. if (!empty($this->multifeed_url))
  1078. {
  1079. $i = 0;
  1080. $success = 0;
  1081. $this->multifeed_objects = array();
  1082. $this->error = array();
  1083. foreach ($this->multifeed_url as $url)
  1084. {
  1085. $this->multifeed_objects[$i] = clone $this;
  1086. $this->multifeed_objects[$i]->set_feed_url($url);
  1087. $single_success = $this->multifeed_objects[$i]->init();
  1088. $success |= $single_success;
  1089. if (!$single_success)
  1090. {
  1091. $this->error[$i] = $this->multifeed_objects[$i]->error();
  1092. }
  1093. $i++;
  1094. }
  1095. return (bool) $success;
  1096. }
  1097. elseif ($this->feed_url === null && $this->raw_data === null)
  1098. {
  1099. return false;
  1100. }
  1101. $this->error = null;
  1102. $this->data = array();
  1103. $this->multifeed_objects = array();
  1104. $cache = false;
  1105. if ($this->feed_url !== null)
  1106. {
  1107. $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
  1108. // Decide whether to enable caching
  1109. if ($this->cache && $parsed_feed_url['scheme'] !== '')
  1110. {
  1111. $cache = $this->registry->call('Cache', 'create', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
  1112. }
  1113. // Fetch the data via SimplePie_File into $this->raw_data
  1114. if (($fetched = $this->fetch_data($cache)) === true)
  1115. {
  1116. return true;
  1117. }
  1118. elseif ($fetched === false) {
  1119. return false;
  1120. }
  1121. list($headers, $sniffed) = $fetched;
  1122. }
  1123. // Set up array of possible encodings
  1124. $encodings = array();
  1125. // First check to see if input has been overridden.
  1126. if ($this->input_encoding !== false)
  1127. {
  1128. $encodings[] = $this->input_encoding;
  1129. }
  1130. $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
  1131. $text_types = array('text/xml', 'text/xml-external-parsed-entity');
  1132. // RFC 3023 (only applies to sniffed content)
  1133. if (isset($sniffed))
  1134. {
  1135. if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
  1136. {
  1137. if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
  1138. {
  1139. $encodings[] = strtoupper($charset[1]);
  1140. }
  1141. $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
  1142. $encodings[] = 'UTF-8';
  1143. }
  1144. elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
  1145. {
  1146. if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
  1147. {
  1148. $encodings[] = $charset[1];
  1149. }
  1150. $encodings[] = 'US-ASCII';
  1151. }
  1152. // Text MIME-type default
  1153. elseif (substr($sniffed, 0, 5) === 'text/')
  1154. {
  1155. $encodings[] = 'US-ASCII';
  1156. }
  1157. }
  1158. // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
  1159. $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
  1160. $encodings[] = 'UTF-8';
  1161. $encodings[] = 'ISO-8859-1';
  1162. // There's no point in trying an encoding twice
  1163. $encodings = array_unique($encodings);
  1164. // Loop through each possible encoding, till we return something, or run out of possibilities
  1165. foreach ($encodings as $encoding)
  1166. {
  1167. // Change the encoding to UTF-8 (as we always use UTF-8 internally)
  1168. if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
  1169. {
  1170. // Create new parser
  1171. $parser = $this->registry->create('Parser');
  1172. // If it's parsed fine
  1173. if ($parser->parse($utf8_data, 'UTF-8'))
  1174. {
  1175. $this->data = $parser->get_data();
  1176. if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
  1177. {
  1178. $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
  1179. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1180. return false;
  1181. }
  1182. if (isset($headers))
  1183. {
  1184. $this->data['headers'] = $headers;
  1185. }
  1186. $this->data['build'] = SIMPLEPIE_BUILD;
  1187. // Cache the file if caching is enabled
  1188. if ($cache && !$cache->save($this))
  1189. {
  1190. 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);
  1191. }
  1192. return true;
  1193. }
  1194. }
  1195. }
  1196. if (isset($parser))
  1197. {
  1198. // We have an error, just set SimplePie_Misc::error to it and quit
  1199. $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());
  1200. }
  1201. else
  1202. {
  1203. $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.';
  1204. }
  1205. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1206. return false;
  1207. }
  1208. /**
  1209. * Fetch the data via SimplePie_File
  1210. *
  1211. * If the data is already cached, attempt to fetch it from there instead
  1212. * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
  1213. * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
  1214. */
  1215. protected function fetch_data(&$cache)
  1216. {
  1217. // If it's enabled, use the cache
  1218. if ($cache)
  1219. {
  1220. // Load the Cache
  1221. $this->data = $cache->load();
  1222. if (!empty($this->data))
  1223. {
  1224. // If the cache is for an outdated build of SimplePie
  1225. if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
  1226. {
  1227. $cache->unlink();
  1228. $this->data = array();
  1229. }
  1230. // If we've hit a collision just rerun it with caching disabled
  1231. elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
  1232. {
  1233. $cache = false;
  1234. $this->data = array();
  1235. }
  1236. // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
  1237. elseif (isset($this->data['feed_url']))
  1238. {
  1239. // If the autodiscovery cache is still valid use it.
  1240. if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
  1241. {
  1242. // Do not need to do feed autodiscovery yet.
  1243. if ($this->data['feed_url'] !== $this->data['url'])
  1244. {
  1245. $this->set_feed_url($this->data['feed_url']);
  1246. return $this->init();
  1247. }
  1248. $cache->unlink();
  1249. $this->data = array();
  1250. }
  1251. }
  1252. // Check if the cache has been updated
  1253. elseif ($cache->mtime() + $this->cache_duration < time())
  1254. {
  1255. // If we have last-modified and/or etag set
  1256. if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
  1257. {
  1258. $headers = array(
  1259. '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',
  1260. );
  1261. if (isset($this->data['headers']['last-modified']))
  1262. {
  1263. $headers['if-modified-since'] = $this->data['headers']['last-modified'];
  1264. }
  1265. if (isset($this->data['headers']['etag']))
  1266. {
  1267. $headers['if-none-match'] = $this->data['headers']['etag'];
  1268. }
  1269. $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
  1270. if ($file->success)
  1271. {
  1272. if ($file->status_code === 304)
  1273. {
  1274. $cache->touch();
  1275. return true;
  1276. }
  1277. }
  1278. else
  1279. {
  1280. unset($file);
  1281. }
  1282. }
  1283. }
  1284. // If the cache is still valid, just return true
  1285. else
  1286. {
  1287. $this->raw_data = false;
  1288. return true;
  1289. }
  1290. }
  1291. // If the cache is empty, delete it
  1292. else
  1293. {
  1294. $cache->unlink();
  1295. $this->data = array();
  1296. }
  1297. }
  1298. // 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.
  1299. if (!isset($file))
  1300. {
  1301. if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
  1302. {
  1303. $file =& $this->file;
  1304. }
  1305. else
  1306. {
  1307. $headers = array(
  1308. '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',
  1309. );
  1310. $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
  1311. }
  1312. }
  1313. // If the file connection has an error, set SimplePie::error to that and quit
  1314. if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
  1315. {
  1316. $this->error = $file->error;
  1317. return !empty($this->data);
  1318. }
  1319. if (!$this->force_feed)
  1320. {
  1321. // Check if the supplied URL is a feed, if it isn't, look for it.
  1322. $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
  1323. if (!$locate->is_feed($file))
  1324. {
  1325. // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
  1326. unset($file);
  1327. if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
  1328. {
  1329. $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.";
  1330. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1331. return false;
  1332. }
  1333. if ($cache)
  1334. {
  1335. $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
  1336. if (!$cache->save($this))
  1337. {
  1338. 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);
  1339. }
  1340. $cache = $this->registry->call('Cache', 'create', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
  1341. }
  1342. $this->feed_url = $file->url;
  1343. }
  1344. $locate = null;
  1345. }
  1346. $this->raw_data = $file->body;
  1347. $headers = $file->headers;
  1348. $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
  1349. $sniffed = $sniffer->get_type();
  1350. return array($headers, $sniffed);
  1351. }
  1352. /**
  1353. * Get the error message for the occured error
  1354. *
  1355. * @return string|array Error message, or array of messages for multifeeds
  1356. */
  1357. public function error()
  1358. {
  1359. return $this->error;
  1360. }
  1361. /**
  1362. * Get the raw XML
  1363. *
  1364. * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
  1365. * the data instead of printing it.
  1366. *
  1367. * @return string|boolean Raw XML data, false if the cache is used
  1368. */
  1369. public function get_raw_data()
  1370. {
  1371. return $this->raw_data;
  1372. }
  1373. /**
  1374. * Get the character encoding used for output
  1375. *
  1376. * @since Preview Release
  1377. * @return string
  1378. */
  1379. public function get_encoding()
  1380. {
  1381. return $this->sanitize->output_encoding;
  1382. }
  1383. /**
  1384. * Send the content-type header with correct encoding
  1385. *
  1386. * This method ensures that the SimplePie-enabled page is being served with
  1387. * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
  1388. * and character encoding HTTP headers (character encoding determined by the
  1389. * {@see set_output_encoding} config option).
  1390. *
  1391. * This won't work properly if any content or whitespace has already been
  1392. * sent to the browser, because it relies on PHP's
  1393. * {@link http://php.net/header header()} function, and these are the
  1394. * circumstances under which the function works.
  1395. *
  1396. * Because it's setting these settings for the entire page (as is the nature
  1397. * of HTTP headers), this should only be used once per page (again, at the
  1398. * top).
  1399. *
  1400. * @param string $mime MIME type to serve the page as
  1401. */
  1402. public function handle_content_type($mime = 'text/html')
  1403. {
  1404. if (!headers_sent())
  1405. {
  1406. $header = "Content-type: $mime;";
  1407. if ($this->get_encoding())
  1408. {
  1409. $header .= ' charset=' . $this->get_encoding();
  1410. }
  1411. else
  1412. {
  1413. $header .= ' charset=UTF-8';
  1414. }
  1415. header($header);
  1416. }
  1417. }
  1418. /**
  1419. * Get the type of the feed
  1420. *
  1421. * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
  1422. * using {@link http://php.net/language.operators.bitwise bitwise operators}
  1423. *
  1424. * @since 0.8 (usage changed to using constants in 1.0)
  1425. * @see SIMPLEPIE_TYPE_NONE Unknown.
  1426. * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
  1427. * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
  1428. * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
  1429. * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
  1430. * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
  1431. * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
  1432. * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
  1433. * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
  1434. * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
  1435. * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
  1436. * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
  1437. * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
  1438. * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
  1439. * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
  1440. * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
  1441. * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
  1442. * @return int SIMPLEPIE_TYPE_* constant
  1443. */
  1444. public function get_type()
  1445. {
  1446. if (!isset($this->data['type']))
  1447. {
  1448. $this->data['type'] = SIMPLEPIE_TYPE_ALL;
  1449. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
  1450. {
  1451. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
  1452. }
  1453. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
  1454. {
  1455. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
  1456. }
  1457. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
  1458. {
  1459. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
  1460. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
  1461. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
  1462. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
  1463. {
  1464. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
  1465. }
  1466. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
  1467. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
  1468. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
  1469. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
  1470. {
  1471. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
  1472. }
  1473. }
  1474. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
  1475. {
  1476. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
  1477. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  1478. {
  1479. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  1480. {
  1481. case '0.91':
  1482. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
  1483. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  1484. {
  1485. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  1486. {
  1487. case '0':
  1488. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
  1489. break;
  1490. case '24':
  1491. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
  1492. break;
  1493. }
  1494. }
  1495. break;
  1496. case '0.92':
  1497. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
  1498. break;
  1499. case '0.93':
  1500. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
  1501. break;
  1502. case '0.94':
  1503. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
  1504. break;
  1505. case '2.0':
  1506. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
  1507. break;
  1508. }
  1509. }
  1510. }
  1511. else
  1512. {
  1513. $this->data['type'] = SIMPLEPIE_TYPE_NONE;
  1514. }
  1515. }
  1516. return $this->data['type'];
  1517. }
  1518. /**
  1519. * Get the URL for the feed
  1520. *
  1521. * May or may not be different from the URL passed to {@see set_feed_url()},
  1522. * depending on whether auto-discovery was used.
  1523. *
  1524. * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
  1525. * @todo If we have a perm redirect we should return the new URL
  1526. * @todo When we make the above change, let's support <itunes:new-feed-url> as well
  1527. * @todo Also, |atom:link|@rel=self
  1528. * @return string|null
  1529. */
  1530. public function subscribe_url()
  1531. {
  1532. if ($this->feed_url !== null)
  1533. {
  1534. return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
  1535. }
  1536. else
  1537. {
  1538. return null;
  1539. }
  1540. }
  1541. /**
  1542. * Get data for an feed-level element
  1543. *
  1544. * This method allows you to get access to ANY element/attribute that is a
  1545. * sub-element of the opening feed tag.
  1546. *
  1547. * The return value is an indexed array of elements matching the given
  1548. * namespace and tag name. Each element has `attribs`, `data` and `child`
  1549. * subkeys. For `attribs` and `child`, these contain namespace subkeys.
  1550. * `attribs` then has one level of associative name => value data (where
  1551. * `value` is a string) after the namespace. `child` has tag-indexed keys
  1552. * after the namespace, each member of which is an indexed array matching
  1553. * this same format.
  1554. *
  1555. * For example:
  1556. * <pre>
  1557. * // This is probably a bad example because we already support
  1558. * // <media:content> natively, but it shows you how to parse through
  1559. * // the nodes.
  1560. * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
  1561. * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
  1562. * $file = $content[0]['attribs']['']['url'];
  1563. * echo $file;
  1564. * </pre>
  1565. *
  1566. * @since 1.0
  1567. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1568. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1569. * @param string $tag Tag name
  1570. * @return array
  1571. */
  1572. public function get_feed_tags($namespace, $tag)
  1573. {
  1574. $type = $this->get_type();
  1575. if ($type & SIMPLEPIE_TYPE_ATOM_10)
  1576. {
  1577. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
  1578. {
  1579. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
  1580. }
  1581. }
  1582. if ($type & SIMPLEPIE_TYPE_ATOM_03)
  1583. {
  1584. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
  1585. {
  1586. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
  1587. }
  1588. }
  1589. if ($type & SIMPLEPIE_TYPE_RSS_RDF)
  1590. {
  1591. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
  1592. {
  1593. return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
  1594. }
  1595. }
  1596. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1597. {
  1598. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
  1599. {
  1600. return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
  1601. }
  1602. }
  1603. return null;
  1604. }
  1605. /**
  1606. * Get data for an channel-level element
  1607. *
  1608. * This method allows you to get access to ANY element/attribute in the
  1609. * channel/header section of the feed.
  1610. *
  1611. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  1612. *
  1613. * @since 1.0
  1614. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1615. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1616. * @param string $tag Tag name
  1617. * @return array
  1618. */
  1619. public function get_channel_tags($namespace, $tag)
  1620. {
  1621. $type = $this->get_type();
  1622. if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
  1623. {
  1624. if ($return = $this->get_feed_tags($namespace, $tag))
  1625. {
  1626. return $return;
  1627. }
  1628. }
  1629. if ($type & SIMPLEPIE_TYPE_RSS_10)
  1630. {
  1631. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
  1632. {
  1633. if (isset($channel[0]['child'][$namespace][$tag]))
  1634. {
  1635. return $channel[0]['child'][$namespace][$tag];
  1636. }
  1637. }
  1638. }
  1639. if ($type & SIMPLEPIE_TYPE_RSS_090)
  1640. {
  1641. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
  1642. {
  1643. if (isset($channel[0]['child'][$namespace][$tag]))
  1644. {
  1645. return $channel[0]['child'][$namespace][$tag];
  1646. }
  1647. }
  1648. }
  1649. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1650. {
  1651. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
  1652. {
  1653. if (isset($channel[0]['child'][$namespace][$tag]))
  1654. {
  1655. return $channel[0]['child'][$namespace][$tag];
  1656. }
  1657. }
  1658. }
  1659. return null;
  1660. }
  1661. /**
  1662. * Get data for an channel-level element
  1663. *
  1664. * This method allows you to get access to ANY element/attribute in the
  1665. * image/logo section of the feed.
  1666. *
  1667. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  1668. *
  1669. * @since 1.0
  1670. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1671. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1672. * @param string $tag Tag name
  1673. * @return array
  1674. */
  1675. public function get_image_tags($namespace, $tag)
  1676. {
  1677. $type = $this->get_type();
  1678. if ($type & SIMPLEPIE_TYPE_RSS_10)
  1679. {
  1680. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
  1681. {
  1682. if (isset($image[0]['child'][$namespace][$tag]))
  1683. {
  1684. return $image[0]['child'][$namespace][$tag];
  1685. }
  1686. }
  1687. }
  1688. if ($type & SIMPLEPIE_TYPE_RSS_090)
  1689. {
  1690. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
  1691. {
  1692. if (isset($image[0]['child'][$namespace][$tag]))
  1693. {
  1694. return $image[0]['child'][$namespace][$tag];
  1695. }
  1696. }
  1697. }
  1698. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1699. {
  1700. if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
  1701. {
  1702. if (isset($image[0]['child'][$namespace][$tag]))
  1703. {
  1704. return $image[0]['child'][$namespace][$tag];
  1705. }
  1706. }
  1707. }
  1708. return null;
  1709. }
  1710. /**
  1711. * Get the base URL value from the feed
  1712. *
  1713. * Uses `<xml:base>` if available, otherwise uses the first link in the
  1714. * feed, or failing that, the URL of the feed itself.
  1715. *
  1716. * @see get_link
  1717. * @see subscribe_url
  1718. *
  1719. * @param array $element
  1720. * @return string
  1721. */
  1722. public function get_base($element = array())
  1723. {
  1724. if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
  1725. {
  1726. return $element['xml_base'];
  1727. }
  1728. elseif ($this->get_link() !== null)
  1729. {
  1730. return $this->get_link();
  1731. }
  1732. else
  1733. {
  1734. return $this->subscribe_url();
  1735. }
  1736. }
  1737. /**
  1738. * Sanitize feed data
  1739. *
  1740. * @access private
  1741. * @see SimplePie_Sanitize::sanitize()
  1742. * @param string $data Data to sanitize
  1743. * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
  1744. * @param string $base Base URL to resolve URLs against
  1745. * @return string Sanitized data
  1746. */
  1747. public function sanitize($data, $type, $base = '')
  1748. {
  1749. return $this->sanitize->sanitize($data, $type, $base);
  1750. }
  1751. /**
  1752. * Get the title of the feed
  1753. *
  1754. * Uses `<atom:title>`, `<title>` or `<dc:title>`
  1755. *
  1756. * @since 1.0 (previously called `get_feed_title` since 0.8)
  1757. * @return string|null
  1758. */
  1759. public function get_title()
  1760. {
  1761. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  1762. {
  1763. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  1764. }
  1765. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  1766. {
  1767. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  1768. }
  1769. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  1770. {
  1771. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1772. }
  1773. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  1774. {
  1775. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1776. }
  1777. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  1778. {
  1779. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1780. }
  1781. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  1782. {
  1783. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1784. }
  1785. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  1786. {
  1787. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1788. }
  1789. else
  1790. {
  1791. return null;
  1792. }
  1793. }
  1794. /**
  1795. * Get a category for the feed
  1796. *
  1797. * @since Unknown
  1798. * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
  1799. * @return SimplePie_Category|null
  1800. */
  1801. public function get_category($key = 0)
  1802. {
  1803. $categories = $this->get_categories();
  1804. if (isset($categories[$key]))
  1805. {
  1806. return $categories[$key];
  1807. }
  1808. else
  1809. {
  1810. return null;
  1811. }
  1812. }
  1813. /**
  1814. * Get all categories for the feed
  1815. *
  1816. * Uses `<atom:category>`, `<category>` or `<dc:subject>`
  1817. *
  1818. * @since Unknown
  1819. * @return array|null List of {@see SimplePie_Category} objects
  1820. */
  1821. public function get_categories()
  1822. {
  1823. $categories = array();
  1824. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  1825. {
  1826. $term = null;
  1827. $scheme = null;
  1828. $label = null;
  1829. if (isset($category['attribs']['']['term']))
  1830. {
  1831. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  1832. }
  1833. if (isset($category['attribs']['']['scheme']))
  1834. {
  1835. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  1836. }
  1837. if (isset($category['attribs']['']['label']))
  1838. {
  1839. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  1840. }
  1841. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  1842. }
  1843. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  1844. {
  1845. // This is really the label, but keep this as the term also for BC.
  1846. // Label will also work on retrieving because that falls back to term.
  1847. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1848. if (isset($category['attribs']['']['domain']))
  1849. {
  1850. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  1851. }
  1852. else
  1853. {
  1854. $scheme = null;
  1855. }
  1856. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  1857. }
  1858. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  1859. {
  1860. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1861. }
  1862. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  1863. {
  1864. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1865. }
  1866. if (!empty($categories))
  1867. {
  1868. return array_unique($categories);
  1869. }
  1870. else
  1871. {
  1872. return null;
  1873. }
  1874. }
  1875. /**
  1876. * Get an author for the feed
  1877. *
  1878. * @since 1.1
  1879. * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
  1880. * @return SimplePie_Author|null
  1881. */
  1882. public function get_author($key = 0)
  1883. {
  1884. $authors = $this->get_authors();
  1885. if (isset($authors[$key]))
  1886. {
  1887. return $authors[$key];
  1888. }
  1889. else
  1890. {
  1891. return null;
  1892. }
  1893. }
  1894. /**
  1895. * Get all authors for the feed
  1896. *
  1897. * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
  1898. *
  1899. * @since 1.1
  1900. * @return array|null List of {@see SimplePie_Author} objects
  1901. */
  1902. public function get_authors()
  1903. {
  1904. $authors = array();
  1905. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  1906. {
  1907. $name = null;
  1908. $uri = null;
  1909. $email = null;
  1910. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  1911. {
  1912. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1913. }
  1914. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  1915. {
  1916. $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]));
  1917. }
  1918. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  1919. {
  1920. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1921. }
  1922. if ($name !== null || $email !== null || $uri !== null)
  1923. {
  1924. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  1925. }
  1926. }
  1927. if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  1928. {
  1929. $name = null;
  1930. $url = null;
  1931. $email = null;
  1932. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  1933. {
  1934. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1935. }
  1936. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  1937. {
  1938. $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]));
  1939. }
  1940. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  1941. {
  1942. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1943. }
  1944. if ($name !== null || $email !== null || $url !== null)
  1945. {
  1946. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  1947. }
  1948. }
  1949. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  1950. {
  1951. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1952. }
  1953. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  1954. {
  1955. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1956. }
  1957. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  1958. {
  1959. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1960. }
  1961. if (!empty($authors))
  1962. {
  1963. return array_unique($authors);
  1964. }
  1965. else
  1966. {
  1967. return null;
  1968. }
  1969. }
  1970. /**
  1971. * Get a contributor for the feed
  1972. *
  1973. * @since 1.1
  1974. * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
  1975. * @return SimplePie_Author|null
  1976. */
  1977. public function get_contributor($key = 0)
  1978. {
  1979. $contributors = $this->get_contributors();
  1980. if (isset($contributors[$key]))
  1981. {
  1982. return $contributors[$key];
  1983. }
  1984. else
  1985. {
  1986. return null;
  1987. }
  1988. }
  1989. /**
  1990. * Get all contributors for the feed
  1991. *
  1992. * Uses `<atom:contributor>`
  1993. *
  1994. * @since 1.1
  1995. * @return array|null List of {@see SimplePie_Author} objects
  1996. */
  1997. public function get_contributors()
  1998. {
  1999. $contributors = array();
  2000. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  2001. {
  2002. $name = null;
  2003. $uri = null;
  2004. $email = null;
  2005. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  2006. {
  2007. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2008. }
  2009. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  2010. {
  2011. $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]));
  2012. }
  2013. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  2014. {
  2015. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2016. }
  2017. if ($name !== null || $email !== null || $uri !== null)
  2018. {
  2019. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  2020. }
  2021. }
  2022. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  2023. {
  2024. $name = null;
  2025. $url = null;
  2026. $email = null;
  2027. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  2028. {
  2029. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2030. }
  2031. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  2032. {
  2033. $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]));
  2034. }
  2035. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  2036. {
  2037. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2038. }
  2039. if ($name !== null || $email !== null || $url !== null)
  2040. {
  2041. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  2042. }
  2043. }
  2044. if (!empty($contributors))
  2045. {
  2046. return array_unique($contributors);
  2047. }
  2048. else
  2049. {
  2050. return null;
  2051. }
  2052. }
  2053. /**
  2054. * Get a single link for the feed
  2055. *
  2056. * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
  2057. * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
  2058. * @param string $rel The relationship of the link to return
  2059. * @return string|null Link URL
  2060. */
  2061. public function get_link($key = 0, $rel = 'alternate')
  2062. {
  2063. $links = $this->get_links($rel);
  2064. if (isset($links[$key]))
  2065. {
  2066. return $links[$key];
  2067. }
  2068. else
  2069. {
  2070. return null;
  2071. }
  2072. }
  2073. /**
  2074. * Get the permalink for the item
  2075. *
  2076. * Returns the first link available with a relationship of "alternate".
  2077. * Identical to {@see get_link()} with key 0
  2078. *
  2079. * @see get_link
  2080. * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
  2081. * @internal Added for parity between the parent-level and the item/entry-level.
  2082. * @return string|null Link URL
  2083. */
  2084. public function get_permalink()
  2085. {
  2086. return $this->get_link(0);
  2087. }
  2088. /**
  2089. * Get all links for the feed
  2090. *
  2091. * Uses `<atom:link>` or `<link>`
  2092. *
  2093. * @since Beta 2
  2094. * @param string $rel The relationship of links to return
  2095. * @return array|null Links found for the feed (strings)
  2096. */
  2097. public function get_links($rel = 'alternate')
  2098. {
  2099. if (!isset($this->data['links']))
  2100. {
  2101. $this->data['links'] = array();
  2102. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  2103. {
  2104. foreach ($links as $link)
  2105. {
  2106. if (isset($link['attribs']['']['href']))
  2107. {
  2108. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2109. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2110. }
  2111. }
  2112. }
  2113. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  2114. {
  2115. foreach ($links as $link)
  2116. {
  2117. if (isset($link['attribs']['']['href']))
  2118. {
  2119. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2120. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2121. }
  2122. }
  2123. }
  2124. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  2125. {
  2126. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2127. }
  2128. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  2129. {
  2130. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2131. }
  2132. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  2133. {
  2134. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2135. }
  2136. $keys = array_keys($this->data['links']);
  2137. foreach ($keys as $key)
  2138. {
  2139. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  2140. {
  2141. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  2142. {
  2143. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  2144. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  2145. }
  2146. else
  2147. {
  2148. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  2149. }
  2150. }
  2151. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  2152. {
  2153. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  2154. }
  2155. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  2156. }
  2157. }
  2158. if (isset($this->data['links'][$rel]))
  2159. {
  2160. return $this->data['links'][$rel];
  2161. }
  2162. else
  2163. {
  2164. return null;
  2165. }
  2166. }
  2167. public function get_all_discovered_feeds()
  2168. {
  2169. return $this->all_discovered_feeds;
  2170. }
  2171. /**
  2172. * Get the content for the item
  2173. *
  2174. * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
  2175. * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
  2176. *
  2177. * @since 1.0 (previously called `get_feed_description()` since 0.8)
  2178. * @return string|null
  2179. */
  2180. public function get_description()
  2181. {
  2182. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  2183. {
  2184. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2185. }
  2186. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  2187. {
  2188. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2189. }
  2190. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  2191. {
  2192. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  2193. }
  2194. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  2195. {
  2196. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  2197. }
  2198. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  2199. {
  2200. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2201. }
  2202. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  2203. {
  2204. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2205. }
  2206. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  2207. {
  2208. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2209. }
  2210. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  2211. {
  2212. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2213. }
  2214. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  2215. {
  2216. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2217. }
  2218. else
  2219. {
  2220. return null;
  2221. }
  2222. }
  2223. /**
  2224. * Get the copyright info for the feed
  2225. *
  2226. * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
  2227. *
  2228. * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
  2229. * @return string|null
  2230. */
  2231. public function get_copyright()
  2232. {
  2233. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  2234. {
  2235. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2236. }
  2237. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  2238. {
  2239. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2240. }
  2241. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  2242. {
  2243. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2244. }
  2245. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  2246. {
  2247. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2248. }
  2249. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  2250. {
  2251. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2252. }
  2253. else
  2254. {
  2255. return null;
  2256. }
  2257. }
  2258. /**
  2259. * Get the language for the feed
  2260. *
  2261. * Uses `<language>`, `<dc:language>`, or @xml_lang
  2262. *
  2263. * @since 1.0 (previously called `get_feed_language()` since 0.8)
  2264. * @return string|null
  2265. */
  2266. public function get_language()
  2267. {
  2268. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  2269. {
  2270. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2271. }
  2272. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  2273. {
  2274. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2275. }
  2276. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  2277. {
  2278. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2279. }
  2280. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
  2281. {
  2282. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2283. }
  2284. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
  2285. {
  2286. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2287. }
  2288. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
  2289. {
  2290. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2291. }
  2292. elseif (isset($this->data['headers']['content-language']))
  2293. {
  2294. return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
  2295. }
  2296. else
  2297. {
  2298. return null;
  2299. }
  2300. }
  2301. /**
  2302. * Get the latitude coordinates for the item
  2303. *
  2304. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  2305. *
  2306. * Uses `<geo:lat>` or `<georss:point>`
  2307. *
  2308. * @since 1.0
  2309. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  2310. * @link http://www.georss.org/ GeoRSS
  2311. * @return string|null
  2312. */
  2313. public function get_latitude()
  2314. {
  2315. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  2316. {
  2317. return (float) $return[0]['data'];
  2318. }
  2319. 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))
  2320. {
  2321. return (float) $match[1];
  2322. }
  2323. else
  2324. {
  2325. return null;
  2326. }
  2327. }
  2328. /**
  2329. * Get the longitude coordinates for the feed
  2330. *
  2331. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  2332. *
  2333. * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
  2334. *
  2335. * @since 1.0
  2336. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  2337. * @link http://www.georss.org/ GeoRSS
  2338. * @return string|null
  2339. */
  2340. public function get_longitude()
  2341. {
  2342. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  2343. {
  2344. return (float) $return[0]['data'];
  2345. }
  2346. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  2347. {
  2348. return (float) $return[0]['data'];
  2349. }
  2350. 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))
  2351. {
  2352. return (float) $match[2];
  2353. }
  2354. else
  2355. {
  2356. return null;
  2357. }
  2358. }
  2359. /**
  2360. * Get the feed logo's title
  2361. *
  2362. * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
  2363. *
  2364. * Uses `<image><title>` or `<image><dc:title>`
  2365. *
  2366. * @return string|null
  2367. */
  2368. public function get_image_title()
  2369. {
  2370. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  2371. {
  2372. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2373. }
  2374. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  2375. {
  2376. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2377. }
  2378. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  2379. {
  2380. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2381. }
  2382. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  2383. {
  2384. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2385. }
  2386. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  2387. {
  2388. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2389. }
  2390. else
  2391. {
  2392. return null;
  2393. }
  2394. }
  2395. /**
  2396. * Get the feed logo's URL
  2397. *
  2398. * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
  2399. * have a "feed logo" URL. This points directly to the image itself.
  2400. *
  2401. * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
  2402. * `<image><title>` or `<image><dc:title>`
  2403. *
  2404. * @return string|null
  2405. */
  2406. public function get_image_url()
  2407. {
  2408. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
  2409. {
  2410. return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
  2411. }
  2412. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  2413. {
  2414. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2415. }
  2416. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  2417. {
  2418. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2419. }
  2420. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
  2421. {
  2422. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2423. }
  2424. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
  2425. {
  2426. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2427. }
  2428. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2429. {
  2430. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2431. }
  2432. else
  2433. {
  2434. return null;
  2435. }
  2436. }
  2437. /**
  2438. * Get the feed logo's link
  2439. *
  2440. * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
  2441. * points to a human-readable page that the image should link to.
  2442. *
  2443. * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
  2444. * `<image><title>` or `<image><dc:title>`
  2445. *
  2446. * @return string|null
  2447. */
  2448. public function get_image_link()
  2449. {
  2450. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  2451. {
  2452. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2453. }
  2454. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  2455. {
  2456. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2457. }
  2458. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  2459. {
  2460. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2461. }
  2462. else
  2463. {
  2464. return null;
  2465. }
  2466. }
  2467. /**
  2468. * Get the feed logo's link
  2469. *
  2470. * RSS 2.0 feeds are allowed to have a "feed logo" width.
  2471. *
  2472. * Uses `<image><width>` or defaults to 88.0 if no width is specified and
  2473. * the feed is an RSS 2.0 feed.
  2474. *
  2475. * @return int|float|null
  2476. */
  2477. public function get_image_width()
  2478. {
  2479. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
  2480. {
  2481. return round($return[0]['data']);
  2482. }
  2483. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2484. {
  2485. return 88.0;
  2486. }
  2487. else
  2488. {
  2489. return null;
  2490. }
  2491. }
  2492. /**
  2493. * Get the feed logo's height
  2494. *
  2495. * RSS 2.0 feeds are allowed to have a "feed logo" height.
  2496. *
  2497. * Uses `<image><height>` or defaults to 31.0 if no height is specified and
  2498. * the feed is an RSS 2.0 feed.
  2499. *
  2500. * @return int|float|null
  2501. */
  2502. public function get_image_height()
  2503. {
  2504. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
  2505. {
  2506. return round($return[0]['data']);
  2507. }
  2508. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2509. {
  2510. return 31.0;
  2511. }
  2512. else
  2513. {
  2514. return null;
  2515. }
  2516. }
  2517. /**
  2518. * Get the number of items in the feed
  2519. *
  2520. * This is well-suited for {@link http://php.net/for for()} loops with
  2521. * {@see get_item()}
  2522. *
  2523. * @param int $max Maximum value to return. 0 for no limit
  2524. * @return int Number of items in the feed
  2525. */
  2526. public function get_item_quantity($max = 0)
  2527. {
  2528. $max = (int) $max;
  2529. $qty = count($this->get_items());
  2530. if ($max === 0)
  2531. {
  2532. return $qty;
  2533. }
  2534. else
  2535. {
  2536. return ($qty > $max) ? $max : $qty;
  2537. }
  2538. }
  2539. /**
  2540. * Get a single item from the feed
  2541. *
  2542. * This is better suited for {@link http://php.net/for for()} loops, whereas
  2543. * {@see get_items()} is better suited for
  2544. * {@link http://php.net/foreach foreach()} loops.
  2545. *
  2546. * @see get_item_quantity()
  2547. * @since Beta 2
  2548. * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
  2549. * @return SimplePie_Item|null
  2550. */
  2551. public function get_item($key = 0)
  2552. {
  2553. $items = $this->get_items();
  2554. if (isset($items[$key]))
  2555. {
  2556. return $items[$key];
  2557. }
  2558. else
  2559. {
  2560. return null;
  2561. }
  2562. }
  2563. /**
  2564. * Get all items from the feed
  2565. *
  2566. * This is better suited for {@link http://php.net/for for()} loops, whereas
  2567. * {@see get_items()} is better suited for
  2568. * {@link http://php.net/foreach foreach()} loops.
  2569. *
  2570. * @see get_item_quantity
  2571. * @since Beta 2
  2572. * @param int $start Index to start at
  2573. * @param int $end Number of items to return. 0 for all items after `$start`
  2574. * @return array|null List of {@see SimplePie_Item} objects
  2575. */
  2576. public function get_items($start = 0, $end = 0)
  2577. {
  2578. if (!isset($this->data['items']))
  2579. {
  2580. if (!empty($this->multifeed_objects))
  2581. {
  2582. $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
  2583. }
  2584. else
  2585. {
  2586. $this->data['items'] = array();
  2587. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
  2588. {
  2589. $keys = array_keys($items);
  2590. foreach ($keys as $key)
  2591. {
  2592. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2593. }
  2594. }
  2595. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
  2596. {
  2597. $keys = array_keys($items);
  2598. foreach ($keys as $key)
  2599. {
  2600. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2601. }
  2602. }
  2603. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
  2604. {
  2605. $keys = array_keys($items);
  2606. foreach ($keys as $key)
  2607. {
  2608. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2609. }
  2610. }
  2611. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
  2612. {
  2613. $keys = array_keys($items);
  2614. foreach ($keys as $key)
  2615. {
  2616. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2617. }
  2618. }
  2619. if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
  2620. {
  2621. $keys = array_keys($items);
  2622. foreach ($keys as $key)
  2623. {
  2624. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2625. }
  2626. }
  2627. }
  2628. }
  2629. if (!empty($this->data['items']))
  2630. {
  2631. // If we want to order it by date, check if all items have a date, and then sort it
  2632. if ($this->order_by_date && empty($this->multifeed_objects))
  2633. {
  2634. if (!isset($this->data['ordered_items']))
  2635. {
  2636. $do_sort = true;
  2637. foreach ($this->data['items'] as $item)
  2638. {
  2639. if (!$item->get_date('U'))
  2640. {
  2641. $do_sort = false;
  2642. break;
  2643. }
  2644. }
  2645. $item = null;
  2646. $this->data['ordered_items'] = $this->data['items'];
  2647. if ($do_sort)
  2648. {
  2649. usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
  2650. }
  2651. }
  2652. $items = $this->data['ordered_items'];
  2653. }
  2654. else
  2655. {
  2656. $items = $this->data['items'];
  2657. }
  2658. // Slice the data as desired
  2659. if ($end === 0)
  2660. {
  2661. return array_slice($items, $start);
  2662. }
  2663. else
  2664. {
  2665. return array_slice($items, $start, $end);
  2666. }
  2667. }
  2668. else
  2669. {
  2670. return array();
  2671. }
  2672. }
  2673. /**
  2674. * Sorting callback for items
  2675. *
  2676. * @access private
  2677. * @param SimplePie $a
  2678. * @param SimplePie $b
  2679. * @return boolean
  2680. */
  2681. public static function sort_items($a, $b)
  2682. {
  2683. return $a->get_date('U') <= $b->get_date('U');
  2684. }
  2685. /**
  2686. * Merge items from several feeds into one
  2687. *
  2688. * If you're merging multiple feeds together, they need to all have dates
  2689. * for the items or else SimplePie will refuse to sort them.
  2690. *
  2691. * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
  2692. * @param array $urls List of SimplePie feed objects to merge
  2693. * @param int $start Starting item
  2694. * @param int $end Number of items to return
  2695. * @param int $limit Maximum number of items per feed
  2696. * @return array
  2697. */
  2698. public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
  2699. {
  2700. if (is_array($urls) && sizeof($urls) > 0)
  2701. {
  2702. $items = array();
  2703. foreach ($urls as $arg)
  2704. {
  2705. if ($arg instanceof SimplePie)
  2706. {
  2707. $items = array_merge($items, $arg->get_items(0, $limit));
  2708. }
  2709. else
  2710. {
  2711. trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
  2712. }
  2713. }
  2714. $do_sort = true;
  2715. foreach ($items as $item)
  2716. {
  2717. if (!$item->get_date('U'))
  2718. {
  2719. $do_sort = false;
  2720. break;
  2721. }
  2722. }
  2723. $item = null;
  2724. if ($do_sort)
  2725. {
  2726. usort($items, array(get_class($urls[0]), 'sort_items'));
  2727. }
  2728. if ($end === 0)
  2729. {
  2730. return array_slice($items, $start);
  2731. }
  2732. else
  2733. {
  2734. return array_slice($items, $start, $end);
  2735. }
  2736. }
  2737. else
  2738. {
  2739. trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
  2740. return array();
  2741. }
  2742. }
  2743. }
  2744. /**
  2745. * Manages all author-related data
  2746. *
  2747. * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
  2748. *
  2749. * This class can be overloaded with {@see SimplePie::set_author_class()}
  2750. *
  2751. * @package SimplePie
  2752. * @subpackage API
  2753. */
  2754. class SimplePie_Author
  2755. {
  2756. /**
  2757. * Author's name
  2758. *
  2759. * @var string
  2760. * @see get_name()
  2761. */
  2762. var $name;
  2763. /**
  2764. * Author's link
  2765. *
  2766. * @var string
  2767. * @see get_link()
  2768. */
  2769. var $link;
  2770. /**
  2771. * Author's email address
  2772. *
  2773. * @var string
  2774. * @see get_email()
  2775. */
  2776. var $email;
  2777. /**
  2778. * Constructor, used to input the data
  2779. *
  2780. * @param string $name
  2781. * @param string $link
  2782. * @param string $email
  2783. */
  2784. public function __construct($name = null, $link = null, $email = null)
  2785. {
  2786. $this->name = $name;
  2787. $this->link = $link;
  2788. $this->email = $email;
  2789. }
  2790. /**
  2791. * String-ified version
  2792. *
  2793. * @return string
  2794. */
  2795. public function __toString()
  2796. {
  2797. // There is no $this->data here
  2798. return md5(serialize($this));
  2799. }
  2800. /**
  2801. * Author's name
  2802. *
  2803. * @return string|null
  2804. */
  2805. public function get_name()
  2806. {
  2807. if ($this->name !== null)
  2808. {
  2809. return $this->name;
  2810. }
  2811. else
  2812. {
  2813. return null;
  2814. }
  2815. }
  2816. /**
  2817. * Author's link
  2818. *
  2819. * @return string|null
  2820. */
  2821. public function get_link()
  2822. {
  2823. if ($this->link !== null)
  2824. {
  2825. return $this->link;
  2826. }
  2827. else
  2828. {
  2829. return null;
  2830. }
  2831. }
  2832. /**
  2833. * Author's email address
  2834. *
  2835. * @return string|null
  2836. */
  2837. public function get_email()
  2838. {
  2839. if ($this->email !== null)
  2840. {
  2841. return $this->email;
  2842. }
  2843. else
  2844. {
  2845. return null;
  2846. }
  2847. }
  2848. }
  2849. /**
  2850. * Base for cache objects
  2851. *
  2852. * Classes to be used with {@see SimplePie_Cache::register()} are expected
  2853. * to implement this interface.
  2854. *
  2855. * @package SimplePie
  2856. * @subpackage Caching
  2857. */
  2858. interface SimplePie_Cache_Base
  2859. {
  2860. /**
  2861. * Feed cache type
  2862. *
  2863. * @var string
  2864. */
  2865. const TYPE_FEED = 'spc';
  2866. /**
  2867. * Image cache type
  2868. *
  2869. * @var string
  2870. */
  2871. const TYPE_IMAGE = 'spi';
  2872. /**
  2873. * Create a new cache object
  2874. *
  2875. * @param string $location Location string (from SimplePie::$cache_location)
  2876. * @param string $name Unique ID for the cache
  2877. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  2878. */
  2879. public function __construct($location, $name, $type);
  2880. /**
  2881. * Save data to the cache
  2882. *
  2883. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  2884. * @return bool Successfulness
  2885. */
  2886. public function save($data);
  2887. /**
  2888. * Retrieve the data saved to the cache
  2889. *
  2890. * @return array Data for SimplePie::$data
  2891. */
  2892. public function load();
  2893. /**
  2894. * Retrieve the last modified time for the cache
  2895. *
  2896. * @return int Timestamp
  2897. */
  2898. public function mtime();
  2899. /**
  2900. * Set the last modified time to the current time
  2901. *
  2902. * @return bool Success status
  2903. */
  2904. public function touch();
  2905. /**
  2906. * Remove the cache
  2907. *
  2908. * @return bool Success status
  2909. */
  2910. public function unlink();
  2911. }
  2912. /**
  2913. * Base class for database-based caches
  2914. *
  2915. * @package SimplePie
  2916. * @subpackage Caching
  2917. */
  2918. abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
  2919. {
  2920. /**
  2921. * Helper for database conversion
  2922. *
  2923. * Converts a given {@see SimplePie} object into data to be stored
  2924. *
  2925. * @param SimplePie $data
  2926. * @return array First item is the serialized data for storage, second item is the unique ID for this item
  2927. */
  2928. protected static function prepare_simplepie_object_for_cache($data)
  2929. {
  2930. $items = $data->get_items();
  2931. $items_by_id = array();
  2932. if (!empty($items))
  2933. {
  2934. foreach ($items as $item)
  2935. {
  2936. $items_by_id[$item->get_id()] = $item;
  2937. }
  2938. if (count($items_by_id) !== count($items))
  2939. {
  2940. $items_by_id = array();
  2941. foreach ($items as $item)
  2942. {
  2943. $items_by_id[$item->get_id(true)] = $item;
  2944. }
  2945. }
  2946. if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
  2947. {
  2948. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
  2949. }
  2950. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
  2951. {
  2952. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
  2953. }
  2954. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
  2955. {
  2956. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
  2957. }
  2958. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
  2959. {
  2960. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
  2961. }
  2962. else
  2963. {
  2964. $channel = null;
  2965. }
  2966. if ($channel !== null)
  2967. {
  2968. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
  2969. {
  2970. unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
  2971. }
  2972. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
  2973. {
  2974. unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
  2975. }
  2976. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
  2977. {
  2978. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
  2979. }
  2980. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
  2981. {
  2982. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
  2983. }
  2984. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
  2985. {
  2986. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
  2987. }
  2988. }
  2989. if (isset($data->data['items']))
  2990. {
  2991. unset($data->data['items']);
  2992. }
  2993. if (isset($data->data['ordered_items']))
  2994. {
  2995. unset($data->data['ordered_items']);
  2996. }
  2997. }
  2998. return array(serialize($data->data), $items_by_id);
  2999. }
  3000. }
  3001. /**
  3002. * Caches data to the filesystem
  3003. *
  3004. * @package SimplePie
  3005. * @subpackage Caching
  3006. */
  3007. class SimplePie_Cache_File implements SimplePie_Cache_Base
  3008. {
  3009. /**
  3010. * Location string
  3011. *
  3012. * @see SimplePie::$cache_location
  3013. * @var string
  3014. */
  3015. protected $location;
  3016. /**
  3017. * Filename
  3018. *
  3019. * @var string
  3020. */
  3021. protected $filename;
  3022. /**
  3023. * File extension
  3024. *
  3025. * @var string
  3026. */
  3027. protected $extension;
  3028. /**
  3029. * File path
  3030. *
  3031. * @var string
  3032. */
  3033. protected $name;
  3034. /**
  3035. * Create a new cache object
  3036. *
  3037. * @param string $location Location string (from SimplePie::$cache_location)
  3038. * @param string $name Unique ID for the cache
  3039. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3040. */
  3041. public function __construct($location, $name, $type)
  3042. {
  3043. $this->location = $location;
  3044. $this->filename = $name;
  3045. $this->extension = $type;
  3046. $this->name = "$this->location/$this->filename.$this->extension";
  3047. }
  3048. /**
  3049. * Save data to the cache
  3050. *
  3051. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3052. * @return bool Successfulness
  3053. */
  3054. public function save($data)
  3055. {
  3056. if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
  3057. {
  3058. if ($data instanceof SimplePie)
  3059. {
  3060. $data = $data->data;
  3061. }
  3062. $data = serialize($data);
  3063. return (bool) file_put_contents($this->name, $data);
  3064. }
  3065. return false;
  3066. }
  3067. /**
  3068. * Retrieve the data saved to the cache
  3069. *
  3070. * @return array Data for SimplePie::$data
  3071. */
  3072. public function load()
  3073. {
  3074. if (file_exists($this->name) && is_readable($this->name))
  3075. {
  3076. return unserialize(file_get_contents($this->name));
  3077. }
  3078. return false;
  3079. }
  3080. /**
  3081. * Retrieve the last modified time for the cache
  3082. *
  3083. * @return int Timestamp
  3084. */
  3085. public function mtime()
  3086. {
  3087. if (file_exists($this->name))
  3088. {
  3089. return filemtime($this->name);
  3090. }
  3091. return false;
  3092. }
  3093. /**
  3094. * Set the last modified time to the current time
  3095. *
  3096. * @return bool Success status
  3097. */
  3098. public function touch()
  3099. {
  3100. if (file_exists($this->name))
  3101. {
  3102. return touch($this->name);
  3103. }
  3104. return false;
  3105. }
  3106. /**
  3107. * Remove the cache
  3108. *
  3109. * @return bool Success status
  3110. */
  3111. public function unlink()
  3112. {
  3113. if (file_exists($this->name))
  3114. {
  3115. return unlink($this->name);
  3116. }
  3117. return false;
  3118. }
  3119. }
  3120. /**
  3121. * Caches data to memcache
  3122. *
  3123. * Registered for URLs with the "memcache" protocol
  3124. *
  3125. * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
  3126. * connect to memcache on `localhost` on port 11211. All tables will be
  3127. * prefixed with `sp_` and data will expire after 3600 seconds
  3128. *
  3129. * @package SimplePie
  3130. * @subpackage Caching
  3131. * @uses Memcache
  3132. */
  3133. class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
  3134. {
  3135. /**
  3136. * Memcache instance
  3137. *
  3138. * @var Memcache
  3139. */
  3140. protected $cache;
  3141. /**
  3142. * Options
  3143. *
  3144. * @var array
  3145. */
  3146. protected $options;
  3147. /**
  3148. * Cache name
  3149. *
  3150. * @var string
  3151. */
  3152. protected $name;
  3153. /**
  3154. * Create a new cache object
  3155. *
  3156. * @param string $location Location string (from SimplePie::$cache_location)
  3157. * @param string $name Unique ID for the cache
  3158. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3159. */
  3160. public function __construct($location, $name, $type)
  3161. {
  3162. $this->options = array(
  3163. 'host' => '127.0.0.1',
  3164. 'port' => 11211,
  3165. 'extras' => array(
  3166. 'timeout' => 3600, // one hour
  3167. 'prefix' => 'simplepie_',
  3168. ),
  3169. );
  3170. $parsed = SimplePie_Cache::parse_URL($location);
  3171. $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
  3172. $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
  3173. $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
  3174. $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
  3175. $this->cache = new Memcache();
  3176. $this->cache->addServer($this->options['host'], (int) $this->options['port']);
  3177. }
  3178. /**
  3179. * Save data to the cache
  3180. *
  3181. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3182. * @return bool Successfulness
  3183. */
  3184. public function save($data)
  3185. {
  3186. if ($data instanceof SimplePie)
  3187. {
  3188. $data = $data->data;
  3189. }
  3190. return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
  3191. }
  3192. /**
  3193. * Retrieve the data saved to the cache
  3194. *
  3195. * @return array Data for SimplePie::$data
  3196. */
  3197. public function load()
  3198. {
  3199. $data = $this->cache->get($this->name);
  3200. if ($data !== false)
  3201. {
  3202. return unserialize($data);
  3203. }
  3204. return false;
  3205. }
  3206. /**
  3207. * Retrieve the last modified time for the cache
  3208. *
  3209. * @return int Timestamp
  3210. */
  3211. public function mtime()
  3212. {
  3213. $data = $this->cache->get($this->name);
  3214. if ($data !== false)
  3215. {
  3216. // essentially ignore the mtime because Memcache expires on it's own
  3217. return time();
  3218. }
  3219. return false;
  3220. }
  3221. /**
  3222. * Set the last modified time to the current time
  3223. *
  3224. * @return bool Success status
  3225. */
  3226. public function touch()
  3227. {
  3228. $data = $this->cache->get($this->name);
  3229. if ($data !== false)
  3230. {
  3231. return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
  3232. }
  3233. return false;
  3234. }
  3235. /**
  3236. * Remove the cache
  3237. *
  3238. * @return bool Success status
  3239. */
  3240. public function unlink()
  3241. {
  3242. return $this->cache->delete($this->name, 0);
  3243. }
  3244. }
  3245. /**
  3246. * Caches data to a MySQL database
  3247. *
  3248. * Registered for URLs with the "mysql" protocol
  3249. *
  3250. * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
  3251. * connect to the `mydb` database on `localhost` on port 3306, with the user
  3252. * `root` and the password `password`. All tables will be prefixed with `sp_`
  3253. *
  3254. * @package SimplePie
  3255. * @subpackage Caching
  3256. */
  3257. class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
  3258. {
  3259. /**
  3260. * PDO instance
  3261. *
  3262. * @var PDO
  3263. */
  3264. protected $mysql;
  3265. /**
  3266. * Options
  3267. *
  3268. * @var array
  3269. */
  3270. protected $options;
  3271. /**
  3272. * Cache ID
  3273. *
  3274. * @var string
  3275. */
  3276. protected $id;
  3277. /**
  3278. * Create a new cache object
  3279. *
  3280. * @param string $location Location string (from SimplePie::$cache_location)
  3281. * @param string $name Unique ID for the cache
  3282. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3283. */
  3284. public function __construct($location, $name, $type)
  3285. {
  3286. $this->options = array(
  3287. 'user' => null,
  3288. 'pass' => null,
  3289. 'host' => '127.0.0.1',
  3290. 'port' => '3306',
  3291. 'path' => '',
  3292. 'extras' => array(
  3293. 'prefix' => '',
  3294. ),
  3295. );
  3296. $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
  3297. // Path is prefixed with a "/"
  3298. $this->options['dbname'] = substr($this->options['path'], 1);
  3299. try
  3300. {
  3301. $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'));
  3302. }
  3303. catch (PDOException $e)
  3304. {
  3305. $this->mysql = null;
  3306. return;
  3307. }
  3308. $this->id = $name . $type;
  3309. if (!$query = $this->mysql->query('SHOW TABLES'))
  3310. {
  3311. $this->mysql = null;
  3312. return;
  3313. }
  3314. $db = array();
  3315. while ($row = $query->fetchColumn())
  3316. {
  3317. $db[] = $row;
  3318. }
  3319. if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
  3320. {
  3321. $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)))');
  3322. if ($query === false)
  3323. {
  3324. $this->mysql = null;
  3325. }
  3326. }
  3327. if (!in_array($this->options['extras']['prefix'] . 'items', $db))
  3328. {
  3329. $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)))');
  3330. if ($query === false)
  3331. {
  3332. $this->mysql = null;
  3333. }
  3334. }
  3335. }
  3336. /**
  3337. * Save data to the cache
  3338. *
  3339. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3340. * @return bool Successfulness
  3341. */
  3342. public function save($data)
  3343. {
  3344. if ($this->mysql === null)
  3345. {
  3346. return false;
  3347. }
  3348. if ($data instanceof SimplePie)
  3349. {
  3350. $data = clone $data;
  3351. $prepared = self::prepare_simplepie_object_for_cache($data);
  3352. $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
  3353. $query->bindValue(':feed', $this->id);
  3354. if ($query->execute())
  3355. {
  3356. if ($query->fetchColumn() > 0)
  3357. {
  3358. $items = count($prepared[1]);
  3359. if ($items)
  3360. {
  3361. $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
  3362. $query = $this->mysql->prepare($sql);
  3363. $query->bindValue(':items', $items);
  3364. }
  3365. else
  3366. {
  3367. $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
  3368. $query = $this->mysql->prepare($sql);
  3369. }
  3370. $query->bindValue(':data', $prepared[0]);
  3371. $query->bindValue(':time', time());
  3372. $query->bindValue(':feed', $this->id);
  3373. if (!$query->execute())
  3374. {
  3375. return false;
  3376. }
  3377. }
  3378. else
  3379. {
  3380. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
  3381. $query->bindValue(':feed', $this->id);
  3382. $query->bindValue(':count', count($prepared[1]));
  3383. $query->bindValue(':data', $prepared[0]);
  3384. $query->bindValue(':time', time());
  3385. if (!$query->execute())
  3386. {
  3387. return false;
  3388. }
  3389. }
  3390. $ids = array_keys($prepared[1]);
  3391. if (!empty($ids))
  3392. {
  3393. foreach ($ids as $id)
  3394. {
  3395. $database_ids[] = $this->mysql->quote($id);
  3396. }
  3397. $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
  3398. $query->bindValue(':feed', $this->id);
  3399. if ($query->execute())
  3400. {
  3401. $existing_ids = array();
  3402. while ($row = $query->fetchColumn())
  3403. {
  3404. $existing_ids[] = $row;
  3405. }
  3406. $new_ids = array_diff($ids, $existing_ids);
  3407. foreach ($new_ids as $new_id)
  3408. {
  3409. if (!($date = $prepared[1][$new_id]->get_date('U')))
  3410. {
  3411. $date = time();
  3412. }
  3413. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
  3414. $query->bindValue(':feed', $this->id);
  3415. $query->bindValue(':id', $new_id);
  3416. $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
  3417. $query->bindValue(':date', $date);
  3418. if (!$query->execute())
  3419. {
  3420. return false;
  3421. }
  3422. }
  3423. return true;
  3424. }
  3425. }
  3426. else
  3427. {
  3428. return true;
  3429. }
  3430. }
  3431. }
  3432. else
  3433. {
  3434. $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
  3435. $query->bindValue(':feed', $this->id);
  3436. if ($query->execute())
  3437. {
  3438. if ($query->rowCount() > 0)
  3439. {
  3440. $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
  3441. $query->bindValue(':data', serialize($data));
  3442. $query->bindValue(':time', time());
  3443. $query->bindValue(':feed', $this->id);
  3444. if ($this->execute())
  3445. {
  3446. return true;
  3447. }
  3448. }
  3449. else
  3450. {
  3451. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
  3452. $query->bindValue(':id', $this->id);
  3453. $query->bindValue(':data', serialize($data));
  3454. $query->bindValue(':time', time());
  3455. if ($query->execute())
  3456. {
  3457. return true;
  3458. }
  3459. }
  3460. }
  3461. }
  3462. return false;
  3463. }
  3464. /**
  3465. * Retrieve the data saved to the cache
  3466. *
  3467. * @return array Data for SimplePie::$data
  3468. */
  3469. public function load()
  3470. {
  3471. if ($this->mysql === null)
  3472. {
  3473. return false;
  3474. }
  3475. $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3476. $query->bindValue(':id', $this->id);
  3477. if ($query->execute() && ($row = $query->fetch()))
  3478. {
  3479. $data = unserialize($row[1]);
  3480. if (isset($this->options['items'][0]))
  3481. {
  3482. $items = (int) $this->options['items'][0];
  3483. }
  3484. else
  3485. {
  3486. $items = (int) $row[0];
  3487. }
  3488. if ($items !== 0)
  3489. {
  3490. if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
  3491. {
  3492. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
  3493. }
  3494. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
  3495. {
  3496. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
  3497. }
  3498. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
  3499. {
  3500. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
  3501. }
  3502. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
  3503. {
  3504. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
  3505. }
  3506. else
  3507. {
  3508. $feed = null;
  3509. }
  3510. if ($feed !== null)
  3511. {
  3512. $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
  3513. if ($items > 0)
  3514. {
  3515. $sql .= ' LIMIT ' . $items;
  3516. }
  3517. $query = $this->mysql->prepare($sql);
  3518. $query->bindValue(':feed', $this->id);
  3519. if ($query->execute())
  3520. {
  3521. while ($row = $query->fetchColumn())
  3522. {
  3523. $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
  3524. }
  3525. }
  3526. else
  3527. {
  3528. return false;
  3529. }
  3530. }
  3531. }
  3532. return $data;
  3533. }
  3534. return false;
  3535. }
  3536. /**
  3537. * Retrieve the last modified time for the cache
  3538. *
  3539. * @return int Timestamp
  3540. */
  3541. public function mtime()
  3542. {
  3543. if ($this->mysql === null)
  3544. {
  3545. return false;
  3546. }
  3547. $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3548. $query->bindValue(':id', $this->id);
  3549. if ($query->execute() && ($time = $query->fetchColumn()))
  3550. {
  3551. return $time;
  3552. }
  3553. else
  3554. {
  3555. return false;
  3556. }
  3557. }
  3558. /**
  3559. * Set the last modified time to the current time
  3560. *
  3561. * @return bool Success status
  3562. */
  3563. public function touch()
  3564. {
  3565. if ($this->mysql === null)
  3566. {
  3567. return false;
  3568. }
  3569. $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
  3570. $query->bindValue(':time', time());
  3571. $query->bindValue(':id', $this->id);
  3572. if ($query->execute() && $query->rowCount() > 0)
  3573. {
  3574. return true;
  3575. }
  3576. else
  3577. {
  3578. return false;
  3579. }
  3580. }
  3581. /**
  3582. * Remove the cache
  3583. *
  3584. * @return bool Success status
  3585. */
  3586. public function unlink()
  3587. {
  3588. if ($this->mysql === null)
  3589. {
  3590. return false;
  3591. }
  3592. $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3593. $query->bindValue(':id', $this->id);
  3594. $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
  3595. $query2->bindValue(':id', $this->id);
  3596. if ($query->execute() && $query2->execute())
  3597. {
  3598. return true;
  3599. }
  3600. else
  3601. {
  3602. return false;
  3603. }
  3604. }
  3605. }
  3606. /**
  3607. * Used to create cache objects
  3608. *
  3609. * This class can be overloaded with {@see SimplePie::set_cache_class()},
  3610. * although the preferred way is to create your own handler
  3611. * via {@see register()}
  3612. *
  3613. * @package SimplePie
  3614. * @subpackage Caching
  3615. */
  3616. class SimplePie_Cache
  3617. {
  3618. /**
  3619. * Cache handler classes
  3620. *
  3621. * These receive 3 parameters to their constructor, as documented in
  3622. * {@see register()}
  3623. * @var array
  3624. */
  3625. protected static $handlers = array(
  3626. 'mysql' => 'SimplePie_Cache_MySQL',
  3627. 'memcache' => 'SimplePie_Cache_Memcache',
  3628. );
  3629. /**
  3630. * Don't call the constructor. Please.
  3631. */
  3632. private function __construct() { }
  3633. /**
  3634. * Create a new SimplePie_Cache object
  3635. *
  3636. * @param string $location URL location (scheme is used to determine handler)
  3637. * @param string $filename Unique identifier for cache object
  3638. * @param string $extension 'spi' or 'spc'
  3639. * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
  3640. */
  3641. public static function create($location, $filename, $extension)
  3642. {
  3643. $type = explode(':', $location, 2);
  3644. $type = $type[0];
  3645. if (!empty(self::$handlers[$type]))
  3646. {
  3647. $class = self::$handlers[$type];
  3648. return new $class($location, $filename, $extension);
  3649. }
  3650. return new SimplePie_Cache_File($location, $filename, $extension);
  3651. }
  3652. /**
  3653. * Register a handler
  3654. *
  3655. * @param string $type DSN type to register for
  3656. * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
  3657. */
  3658. public static function register($type, $class)
  3659. {
  3660. self::$handlers[$type] = $class;
  3661. }
  3662. /**
  3663. * Parse a URL into an array
  3664. *
  3665. * @param string $url
  3666. * @return array
  3667. */
  3668. public static function parse_URL($url)
  3669. {
  3670. $params = parse_url($url);
  3671. $params['extras'] = array();
  3672. if (isset($params['query']))
  3673. {
  3674. parse_str($params['query'], $params['extras']);
  3675. }
  3676. return $params;
  3677. }
  3678. }
  3679. /**
  3680. * Handles `<media:text>` captions as defined in Media RSS.
  3681. *
  3682. * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
  3683. *
  3684. * This class can be overloaded with {@see SimplePie::set_caption_class()}
  3685. *
  3686. * @package SimplePie
  3687. * @subpackage API
  3688. */
  3689. class SimplePie_Caption
  3690. {
  3691. /**
  3692. * Content type
  3693. *
  3694. * @var string
  3695. * @see get_type()
  3696. */
  3697. var $type;
  3698. /**
  3699. * Language
  3700. *
  3701. * @var string
  3702. * @see get_language()
  3703. */
  3704. var $lang;
  3705. /**
  3706. * Start time
  3707. *
  3708. * @var string
  3709. * @see get_starttime()
  3710. */
  3711. var $startTime;
  3712. /**
  3713. * End time
  3714. *
  3715. * @var string
  3716. * @see get_endtime()
  3717. */
  3718. var $endTime;
  3719. /**
  3720. * Caption text
  3721. *
  3722. * @var string
  3723. * @see get_text()
  3724. */
  3725. var $text;
  3726. /**
  3727. * Constructor, used to input the data
  3728. *
  3729. * For documentation on all the parameters, see the corresponding
  3730. * properties and their accessors
  3731. */
  3732. public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
  3733. {
  3734. $this->type = $type;
  3735. $this->lang = $lang;
  3736. $this->startTime = $startTime;
  3737. $this->endTime = $endTime;
  3738. $this->text = $text;
  3739. }
  3740. /**
  3741. * String-ified version
  3742. *
  3743. * @return string
  3744. */
  3745. public function __toString()
  3746. {
  3747. // There is no $this->data here
  3748. return md5(serialize($this));
  3749. }
  3750. /**
  3751. * Get the end time
  3752. *
  3753. * @return string|null Time in the format 'hh:mm:ss.SSS'
  3754. */
  3755. public function get_endtime()
  3756. {
  3757. if ($this->endTime !== null)
  3758. {
  3759. return $this->endTime;
  3760. }
  3761. else
  3762. {
  3763. return null;
  3764. }
  3765. }
  3766. /**
  3767. * Get the language
  3768. *
  3769. * @link http://tools.ietf.org/html/rfc3066
  3770. * @return string|null Language code as per RFC 3066
  3771. */
  3772. public function get_language()
  3773. {
  3774. if ($this->lang !== null)
  3775. {
  3776. return $this->lang;
  3777. }
  3778. else
  3779. {
  3780. return null;
  3781. }
  3782. }
  3783. /**
  3784. * Get the start time
  3785. *
  3786. * @return string|null Time in the format 'hh:mm:ss.SSS'
  3787. */
  3788. public function get_starttime()
  3789. {
  3790. if ($this->startTime !== null)
  3791. {
  3792. return $this->startTime;
  3793. }
  3794. else
  3795. {
  3796. return null;
  3797. }
  3798. }
  3799. /**
  3800. * Get the text of the caption
  3801. *
  3802. * @return string|null
  3803. */
  3804. public function get_text()
  3805. {
  3806. if ($this->text !== null)
  3807. {
  3808. return $this->text;
  3809. }
  3810. else
  3811. {
  3812. return null;
  3813. }
  3814. }
  3815. /**
  3816. * Get the content type (not MIME type)
  3817. *
  3818. * @return string|null Either 'text' or 'html'
  3819. */
  3820. public function get_type()
  3821. {
  3822. if ($this->type !== null)
  3823. {
  3824. return $this->type;
  3825. }
  3826. else
  3827. {
  3828. return null;
  3829. }
  3830. }
  3831. }
  3832. /**
  3833. * Manages all category-related data
  3834. *
  3835. * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
  3836. *
  3837. * This class can be overloaded with {@see SimplePie::set_category_class()}
  3838. *
  3839. * @package SimplePie
  3840. * @subpackage API
  3841. */
  3842. class SimplePie_Category
  3843. {
  3844. /**
  3845. * Category identifier
  3846. *
  3847. * @var string
  3848. * @see get_term
  3849. */
  3850. var $term;
  3851. /**
  3852. * Categorization scheme identifier
  3853. *
  3854. * @var string
  3855. * @see get_scheme()
  3856. */
  3857. var $scheme;
  3858. /**
  3859. * Human readable label
  3860. *
  3861. * @var string
  3862. * @see get_label()
  3863. */
  3864. var $label;
  3865. /**
  3866. * Constructor, used to input the data
  3867. *
  3868. * @param string $term
  3869. * @param string $scheme
  3870. * @param string $label
  3871. */
  3872. public function __construct($term = null, $scheme = null, $label = null)
  3873. {
  3874. $this->term = $term;
  3875. $this->scheme = $scheme;
  3876. $this->label = $label;
  3877. }
  3878. /**
  3879. * String-ified version
  3880. *
  3881. * @return string
  3882. */
  3883. public function __toString()
  3884. {
  3885. // There is no $this->data here
  3886. return md5(serialize($this));
  3887. }
  3888. /**
  3889. * Get the category identifier
  3890. *
  3891. * @return string|null
  3892. */
  3893. public function get_term()
  3894. {
  3895. if ($this->term !== null)
  3896. {
  3897. return $this->term;
  3898. }
  3899. else
  3900. {
  3901. return null;
  3902. }
  3903. }
  3904. /**
  3905. * Get the categorization scheme identifier
  3906. *
  3907. * @return string|null
  3908. */
  3909. public function get_scheme()
  3910. {
  3911. if ($this->scheme !== null)
  3912. {
  3913. return $this->scheme;
  3914. }
  3915. else
  3916. {
  3917. return null;
  3918. }
  3919. }
  3920. /**
  3921. * Get the human readable label
  3922. *
  3923. * @return string|null
  3924. */
  3925. public function get_label()
  3926. {
  3927. if ($this->label !== null)
  3928. {
  3929. return $this->label;
  3930. }
  3931. else
  3932. {
  3933. return $this->get_term();
  3934. }
  3935. }
  3936. }
  3937. /**
  3938. * Content-type sniffing
  3939. *
  3940. * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
  3941. *
  3942. * This is used since we can't always trust Content-Type headers, and is based
  3943. * upon the HTML5 parsing rules.
  3944. *
  3945. *
  3946. * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
  3947. *
  3948. * @package SimplePie
  3949. * @subpackage HTTP
  3950. */
  3951. class SimplePie_Content_Type_Sniffer
  3952. {
  3953. /**
  3954. * File object
  3955. *
  3956. * @var SimplePie_File
  3957. */
  3958. var $file;
  3959. /**
  3960. * Create an instance of the class with the input file
  3961. *
  3962. * @param SimplePie_Content_Type_Sniffer $file Input file
  3963. */
  3964. public function __construct($file)
  3965. {
  3966. $this->file = $file;
  3967. }
  3968. /**
  3969. * Get the Content-Type of the specified file
  3970. *
  3971. * @return string Actual Content-Type
  3972. */
  3973. public function get_type()
  3974. {
  3975. if (isset($this->file->headers['content-type']))
  3976. {
  3977. if (!isset($this->file->headers['content-encoding'])
  3978. && ($this->file->headers['content-type'] === 'text/plain'
  3979. || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
  3980. || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
  3981. || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
  3982. {
  3983. return $this->text_or_binary();
  3984. }
  3985. if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
  3986. {
  3987. $official = substr($this->file->headers['content-type'], 0, $pos);
  3988. }
  3989. else
  3990. {
  3991. $official = $this->file->headers['content-type'];
  3992. }
  3993. $official = trim(strtolower($official));
  3994. if ($official === 'unknown/unknown'
  3995. || $official === 'application/unknown')
  3996. {
  3997. return $this->unknown();
  3998. }
  3999. elseif (substr($official, -4) === '+xml'
  4000. || $official === 'text/xml'
  4001. || $official === 'application/xml')
  4002. {
  4003. return $official;
  4004. }
  4005. elseif (substr($official, 0, 6) === 'image/')
  4006. {
  4007. if ($return = $this->image())
  4008. {
  4009. return $return;
  4010. }
  4011. else
  4012. {
  4013. return $official;
  4014. }
  4015. }
  4016. elseif ($official === 'text/html')
  4017. {
  4018. return $this->feed_or_html();
  4019. }
  4020. else
  4021. {
  4022. return $official;
  4023. }
  4024. }
  4025. else
  4026. {
  4027. return $this->unknown();
  4028. }
  4029. }
  4030. /**
  4031. * Sniff text or binary
  4032. *
  4033. * @return string Actual Content-Type
  4034. */
  4035. public function text_or_binary()
  4036. {
  4037. if (substr($this->file->body, 0, 2) === "\xFE\xFF"
  4038. || substr($this->file->body, 0, 2) === "\xFF\xFE"
  4039. || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
  4040. || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
  4041. {
  4042. return 'text/plain';
  4043. }
  4044. elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
  4045. {
  4046. return 'application/octect-stream';
  4047. }
  4048. else
  4049. {
  4050. return 'text/plain';
  4051. }
  4052. }
  4053. /**
  4054. * Sniff unknown
  4055. *
  4056. * @return string Actual Content-Type
  4057. */
  4058. public function unknown()
  4059. {
  4060. $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
  4061. if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
  4062. || strtolower(substr($this->file->body, $ws, 5)) === '<html'
  4063. || strtolower(substr($this->file->body, $ws, 7)) === '<script')
  4064. {
  4065. return 'text/html';
  4066. }
  4067. elseif (substr($this->file->body, 0, 5) === '%PDF-')
  4068. {
  4069. return 'application/pdf';
  4070. }
  4071. elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
  4072. {
  4073. return 'application/postscript';
  4074. }
  4075. elseif (substr($this->file->body, 0, 6) === 'GIF87a'
  4076. || substr($this->file->body, 0, 6) === 'GIF89a')
  4077. {
  4078. return 'image/gif';
  4079. }
  4080. elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
  4081. {
  4082. return 'image/png';
  4083. }
  4084. elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
  4085. {
  4086. return 'image/jpeg';
  4087. }
  4088. elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
  4089. {
  4090. return 'image/bmp';
  4091. }
  4092. elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
  4093. {
  4094. return 'image/vnd.microsoft.icon';
  4095. }
  4096. else
  4097. {
  4098. return $this->text_or_binary();
  4099. }
  4100. }
  4101. /**
  4102. * Sniff images
  4103. *
  4104. * @return string Actual Content-Type
  4105. */
  4106. public function image()
  4107. {
  4108. if (substr($this->file->body, 0, 6) === 'GIF87a'
  4109. || substr($this->file->body, 0, 6) === 'GIF89a')
  4110. {
  4111. return 'image/gif';
  4112. }
  4113. elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
  4114. {
  4115. return 'image/png';
  4116. }
  4117. elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
  4118. {
  4119. return 'image/jpeg';
  4120. }
  4121. elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
  4122. {
  4123. return 'image/bmp';
  4124. }
  4125. elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
  4126. {
  4127. return 'image/vnd.microsoft.icon';
  4128. }
  4129. else
  4130. {
  4131. return false;
  4132. }
  4133. }
  4134. /**
  4135. * Sniff HTML
  4136. *
  4137. * @return string Actual Content-Type
  4138. */
  4139. public function feed_or_html()
  4140. {
  4141. $len = strlen($this->file->body);
  4142. $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
  4143. while ($pos < $len)
  4144. {
  4145. switch ($this->file->body[$pos])
  4146. {
  4147. case "\x09":
  4148. case "\x0A":
  4149. case "\x0D":
  4150. case "\x20":
  4151. $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
  4152. continue 2;
  4153. case '<':
  4154. $pos++;
  4155. break;
  4156. default:
  4157. return 'text/html';
  4158. }
  4159. if (substr($this->file->body, $pos, 3) === '!--')
  4160. {
  4161. $pos += 3;
  4162. if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
  4163. {
  4164. $pos += 3;
  4165. }
  4166. else
  4167. {
  4168. return 'text/html';
  4169. }
  4170. }
  4171. elseif (substr($this->file->body, $pos, 1) === '!')
  4172. {
  4173. if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
  4174. {
  4175. $pos++;
  4176. }
  4177. else
  4178. {
  4179. return 'text/html';
  4180. }
  4181. }
  4182. elseif (substr($this->file->body, $pos, 1) === '?')
  4183. {
  4184. if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
  4185. {
  4186. $pos += 2;
  4187. }
  4188. else
  4189. {
  4190. return 'text/html';
  4191. }
  4192. }
  4193. elseif (substr($this->file->body, $pos, 3) === 'rss'
  4194. || substr($this->file->body, $pos, 7) === 'rdf:RDF')
  4195. {
  4196. return 'application/rss+xml';
  4197. }
  4198. elseif (substr($this->file->body, $pos, 4) === 'feed')
  4199. {
  4200. return 'application/atom+xml';
  4201. }
  4202. else
  4203. {
  4204. return 'text/html';
  4205. }
  4206. }
  4207. return 'text/html';
  4208. }
  4209. }
  4210. /**
  4211. * Manages `<media:copyright>` copyright tags as defined in Media RSS
  4212. *
  4213. * Used by {@see SimplePie_Enclosure::get_copyright()}
  4214. *
  4215. * This class can be overloaded with {@see SimplePie::set_copyright_class()}
  4216. *
  4217. * @package SimplePie
  4218. * @subpackage API
  4219. */
  4220. class SimplePie_Copyright
  4221. {
  4222. /**
  4223. * Copyright URL
  4224. *
  4225. * @var string
  4226. * @see get_url()
  4227. */
  4228. var $url;
  4229. /**
  4230. * Attribution
  4231. *
  4232. * @var string
  4233. * @see get_attribution()
  4234. */
  4235. var $label;
  4236. /**
  4237. * Constructor, used to input the data
  4238. *
  4239. * For documentation on all the parameters, see the corresponding
  4240. * properties and their accessors
  4241. */
  4242. public function __construct($url = null, $label = null)
  4243. {
  4244. $this->url = $url;
  4245. $this->label = $label;
  4246. }
  4247. /**
  4248. * String-ified version
  4249. *
  4250. * @return string
  4251. */
  4252. public function __toString()
  4253. {
  4254. // There is no $this->data here
  4255. return md5(serialize($this));
  4256. }
  4257. /**
  4258. * Get the copyright URL
  4259. *
  4260. * @return string|null URL to copyright information
  4261. */
  4262. public function get_url()
  4263. {
  4264. if ($this->url !== null)
  4265. {
  4266. return $this->url;
  4267. }
  4268. else
  4269. {
  4270. return null;
  4271. }
  4272. }
  4273. /**
  4274. * Get the attribution text
  4275. *
  4276. * @return string|null
  4277. */
  4278. public function get_attribution()
  4279. {
  4280. if ($this->label !== null)
  4281. {
  4282. return $this->label;
  4283. }
  4284. else
  4285. {
  4286. return null;
  4287. }
  4288. }
  4289. }
  4290. /**
  4291. * SimplePie class.
  4292. *
  4293. * Class for backward compatibility.
  4294. *
  4295. * @deprecated Use {@see SimplePie} directly
  4296. * @package SimplePie
  4297. * @subpackage API
  4298. */
  4299. class SimplePie_Core extends SimplePie
  4300. {
  4301. }
  4302. /**
  4303. * Handles `<media:credit>` as defined in Media RSS
  4304. *
  4305. * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
  4306. *
  4307. * This class can be overloaded with {@see SimplePie::set_credit_class()}
  4308. *
  4309. * @package SimplePie
  4310. * @subpackage API
  4311. */
  4312. class SimplePie_Credit
  4313. {
  4314. /**
  4315. * Credited role
  4316. *
  4317. * @var string
  4318. * @see get_role()
  4319. */
  4320. var $role;
  4321. /**
  4322. * Organizational scheme
  4323. *
  4324. * @var string
  4325. * @see get_scheme()
  4326. */
  4327. var $scheme;
  4328. /**
  4329. * Credited name
  4330. *
  4331. * @var string
  4332. * @see get_name()
  4333. */
  4334. var $name;
  4335. /**
  4336. * Constructor, used to input the data
  4337. *
  4338. * For documentation on all the parameters, see the corresponding
  4339. * properties and their accessors
  4340. */
  4341. public function __construct($role = null, $scheme = null, $name = null)
  4342. {
  4343. $this->role = $role;
  4344. $this->scheme = $scheme;
  4345. $this->name = $name;
  4346. }
  4347. /**
  4348. * String-ified version
  4349. *
  4350. * @return string
  4351. */
  4352. public function __toString()
  4353. {
  4354. // There is no $this->data here
  4355. return md5(serialize($this));
  4356. }
  4357. /**
  4358. * Get the role of the person receiving credit
  4359. *
  4360. * @return string|null
  4361. */
  4362. public function get_role()
  4363. {
  4364. if ($this->role !== null)
  4365. {
  4366. return $this->role;
  4367. }
  4368. else
  4369. {
  4370. return null;
  4371. }
  4372. }
  4373. /**
  4374. * Get the organizational scheme
  4375. *
  4376. * @return string|null
  4377. */
  4378. public function get_scheme()
  4379. {
  4380. if ($this->scheme !== null)
  4381. {
  4382. return $this->scheme;
  4383. }
  4384. else
  4385. {
  4386. return null;
  4387. }
  4388. }
  4389. /**
  4390. * Get the credited person/entity's name
  4391. *
  4392. * @return string|null
  4393. */
  4394. public function get_name()
  4395. {
  4396. if ($this->name !== null)
  4397. {
  4398. return $this->name;
  4399. }
  4400. else
  4401. {
  4402. return null;
  4403. }
  4404. }
  4405. }
  4406. /**
  4407. * Decode HTML Entities
  4408. *
  4409. * This implements HTML5 as of revision 967 (2007-06-28)
  4410. *
  4411. * @deprecated Use DOMDocument instead!
  4412. * @package SimplePie
  4413. */
  4414. class SimplePie_Decode_HTML_Entities
  4415. {
  4416. /**
  4417. * Data to be parsed
  4418. *
  4419. * @access private
  4420. * @var string
  4421. */
  4422. var $data = '';
  4423. /**
  4424. * Currently consumed bytes
  4425. *
  4426. * @access private
  4427. * @var string
  4428. */
  4429. var $consumed = '';
  4430. /**
  4431. * Position of the current byte being parsed
  4432. *
  4433. * @access private
  4434. * @var int
  4435. */
  4436. var $position = 0;
  4437. /**
  4438. * Create an instance of the class with the input data
  4439. *
  4440. * @access public
  4441. * @param string $data Input data
  4442. */
  4443. public function __construct($data)
  4444. {
  4445. $this->data = $data;
  4446. }
  4447. /**
  4448. * Parse the input data
  4449. *
  4450. * @access public
  4451. * @return string Output data
  4452. */
  4453. public function parse()
  4454. {
  4455. while (($this->position = strpos($this->data, '&', $this->position)) !== false)
  4456. {
  4457. $this->consume();
  4458. $this->entity();
  4459. $this->consumed = '';
  4460. }
  4461. return $this->data;
  4462. }
  4463. /**
  4464. * Consume the next byte
  4465. *
  4466. * @access private
  4467. * @return mixed The next byte, or false, if there is no more data
  4468. */
  4469. public function consume()
  4470. {
  4471. if (isset($this->data[$this->position]))
  4472. {
  4473. $this->consumed .= $this->data[$this->position];
  4474. return $this->data[$this->position++];
  4475. }
  4476. else
  4477. {
  4478. return false;
  4479. }
  4480. }
  4481. /**
  4482. * Consume a range of characters
  4483. *
  4484. * @access private
  4485. * @param string $chars Characters to consume
  4486. * @return mixed A series of characters that match the range, or false
  4487. */
  4488. public function consume_range($chars)
  4489. {
  4490. if ($len = strspn($this->data, $chars, $this->position))
  4491. {
  4492. $data = substr($this->data, $this->position, $len);
  4493. $this->consumed .= $data;
  4494. $this->position += $len;
  4495. return $data;
  4496. }
  4497. else
  4498. {
  4499. return false;
  4500. }
  4501. }
  4502. /**
  4503. * Unconsume one byte
  4504. *
  4505. * @access private
  4506. */
  4507. public function unconsume()
  4508. {
  4509. $this->consumed = substr($this->consumed, 0, -1);
  4510. $this->position--;
  4511. }
  4512. /**
  4513. * Decode an entity
  4514. *
  4515. * @access private
  4516. */
  4517. public function entity()
  4518. {
  4519. switch ($this->consume())
  4520. {
  4521. case "\x09":
  4522. case "\x0A":
  4523. case "\x0B":
  4524. case "\x0B":
  4525. case "\x0C":
  4526. case "\x20":
  4527. case "\x3C":
  4528. case "\x26":
  4529. case false:
  4530. break;
  4531. case "\x23":
  4532. switch ($this->consume())
  4533. {
  4534. case "\x78":
  4535. case "\x58":
  4536. $range = '0123456789ABCDEFabcdef';
  4537. $hex = true;
  4538. break;
  4539. default:
  4540. $range = '0123456789';
  4541. $hex = false;
  4542. $this->unconsume();
  4543. break;
  4544. }
  4545. if ($codepoint = $this->consume_range($range))
  4546. {
  4547. 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");
  4548. if ($hex)
  4549. {
  4550. $codepoint = hexdec($codepoint);
  4551. }
  4552. else
  4553. {
  4554. $codepoint = intval($codepoint);
  4555. }
  4556. if (isset($windows_1252_specials[$codepoint]))
  4557. {
  4558. $replacement = $windows_1252_specials[$codepoint];
  4559. }
  4560. else
  4561. {
  4562. $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
  4563. }
  4564. if (!in_array($this->consume(), array(';', false), true))
  4565. {
  4566. $this->unconsume();
  4567. }
  4568. $consumed_length = strlen($this->consumed);
  4569. $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
  4570. $this->position += strlen($replacement) - $consumed_length;
  4571. }
  4572. break;
  4573. default:
  4574. static $entities = array(
  4575. 'Aacute' => "\xC3\x81",
  4576. 'aacute' => "\xC3\xA1",
  4577. 'Aacute;' => "\xC3\x81",
  4578. 'aacute;' => "\xC3\xA1",
  4579. 'Acirc' => "\xC3\x82",
  4580. 'acirc' => "\xC3\xA2",
  4581. 'Acirc;' => "\xC3\x82",
  4582. 'acirc;' => "\xC3\xA2",
  4583. 'acute' => "\xC2\xB4",
  4584. 'acute;' => "\xC2\xB4",
  4585. 'AElig' => "\xC3\x86",
  4586. 'aelig' => "\xC3\xA6",
  4587. 'AElig;' => "\xC3\x86",
  4588. 'aelig;' => "\xC3\xA6",
  4589. 'Agrave' => "\xC3\x80",
  4590. 'agrave' => "\xC3\xA0",
  4591. 'Agrave;' => "\xC3\x80",
  4592. 'agrave;' => "\xC3\xA0",
  4593. 'alefsym;' => "\xE2\x84\xB5",
  4594. 'Alpha;' => "\xCE\x91",
  4595. 'alpha;' => "\xCE\xB1",
  4596. 'AMP' => "\x26",
  4597. 'amp' => "\x26",
  4598. 'AMP;' => "\x26",
  4599. 'amp;' => "\x26",
  4600. 'and;' => "\xE2\x88\xA7",
  4601. 'ang;' => "\xE2\x88\xA0",
  4602. 'apos;' => "\x27",
  4603. 'Aring' => "\xC3\x85",
  4604. 'aring' => "\xC3\xA5",
  4605. 'Aring;' => "\xC3\x85",
  4606. 'aring;' => "\xC3\xA5",
  4607. 'asymp;' => "\xE2\x89\x88",
  4608. 'Atilde' => "\xC3\x83",
  4609. 'atilde' => "\xC3\xA3",
  4610. 'Atilde;' => "\xC3\x83",
  4611. 'atilde;' => "\xC3\xA3",
  4612. 'Auml' => "\xC3\x84",
  4613. 'auml' => "\xC3\xA4",
  4614. 'Auml;' => "\xC3\x84",
  4615. 'auml;' => "\xC3\xA4",
  4616. 'bdquo;' => "\xE2\x80\x9E",
  4617. 'Beta;' => "\xCE\x92",
  4618. 'beta;' => "\xCE\xB2",
  4619. 'brvbar' => "\xC2\xA6",
  4620. 'brvbar;' => "\xC2\xA6",
  4621. 'bull;' => "\xE2\x80\xA2",
  4622. 'cap;' => "\xE2\x88\xA9",
  4623. 'Ccedil' => "\xC3\x87",
  4624. 'ccedil' => "\xC3\xA7",
  4625. 'Ccedil;' => "\xC3\x87",
  4626. 'ccedil;' => "\xC3\xA7",
  4627. 'cedil' => "\xC2\xB8",
  4628. 'cedil;' => "\xC2\xB8",
  4629. 'cent' => "\xC2\xA2",
  4630. 'cent;' => "\xC2\xA2",
  4631. 'Chi;' => "\xCE\xA7",
  4632. 'chi;' => "\xCF\x87",
  4633. 'circ;' => "\xCB\x86",
  4634. 'clubs;' => "\xE2\x99\xA3",
  4635. 'cong;' => "\xE2\x89\x85",
  4636. 'COPY' => "\xC2\xA9",
  4637. 'copy' => "\xC2\xA9",
  4638. 'COPY;' => "\xC2\xA9",
  4639. 'copy;' => "\xC2\xA9",
  4640. 'crarr;' => "\xE2\x86\xB5",
  4641. 'cup;' => "\xE2\x88\xAA",
  4642. 'curren' => "\xC2\xA4",
  4643. 'curren;' => "\xC2\xA4",
  4644. 'Dagger;' => "\xE2\x80\xA1",
  4645. 'dagger;' => "\xE2\x80\xA0",
  4646. 'dArr;' => "\xE2\x87\x93",
  4647. 'darr;' => "\xE2\x86\x93",
  4648. 'deg' => "\xC2\xB0",
  4649. 'deg;' => "\xC2\xB0",
  4650. 'Delta;' => "\xCE\x94",
  4651. 'delta;' => "\xCE\xB4",
  4652. 'diams;' => "\xE2\x99\xA6",
  4653. 'divide' => "\xC3\xB7",
  4654. 'divide;' => "\xC3\xB7",
  4655. 'Eacute' => "\xC3\x89",
  4656. 'eacute' => "\xC3\xA9",
  4657. 'Eacute;' => "\xC3\x89",
  4658. 'eacute;' => "\xC3\xA9",
  4659. 'Ecirc' => "\xC3\x8A",
  4660. 'ecirc' => "\xC3\xAA",
  4661. 'Ecirc;' => "\xC3\x8A",
  4662. 'ecirc;' => "\xC3\xAA",
  4663. 'Egrave' => "\xC3\x88",
  4664. 'egrave' => "\xC3\xA8",
  4665. 'Egrave;' => "\xC3\x88",
  4666. 'egrave;' => "\xC3\xA8",
  4667. 'empty;' => "\xE2\x88\x85",
  4668. 'emsp;' => "\xE2\x80\x83",
  4669. 'ensp;' => "\xE2\x80\x82",
  4670. 'Epsilon;' => "\xCE\x95",
  4671. 'epsilon;' => "\xCE\xB5",
  4672. 'equiv;' => "\xE2\x89\xA1",
  4673. 'Eta;' => "\xCE\x97",
  4674. 'eta;' => "\xCE\xB7",
  4675. 'ETH' => "\xC3\x90",
  4676. 'eth' => "\xC3\xB0",
  4677. 'ETH;' => "\xC3\x90",
  4678. 'eth;' => "\xC3\xB0",
  4679. 'Euml' => "\xC3\x8B",
  4680. 'euml' => "\xC3\xAB",
  4681. 'Euml;' => "\xC3\x8B",
  4682. 'euml;' => "\xC3\xAB",
  4683. 'euro;' => "\xE2\x82\xAC",
  4684. 'exist;' => "\xE2\x88\x83",
  4685. 'fnof;' => "\xC6\x92",
  4686. 'forall;' => "\xE2\x88\x80",
  4687. 'frac12' => "\xC2\xBD",
  4688. 'frac12;' => "\xC2\xBD",
  4689. 'frac14' => "\xC2\xBC",
  4690. 'frac14;' => "\xC2\xBC",
  4691. 'frac34' => "\xC2\xBE",
  4692. 'frac34;' => "\xC2\xBE",
  4693. 'frasl;' => "\xE2\x81\x84",
  4694. 'Gamma;' => "\xCE\x93",
  4695. 'gamma;' => "\xCE\xB3",
  4696. 'ge;' => "\xE2\x89\xA5",
  4697. 'GT' => "\x3E",
  4698. 'gt' => "\x3E",
  4699. 'GT;' => "\x3E",
  4700. 'gt;' => "\x3E",
  4701. 'hArr;' => "\xE2\x87\x94",
  4702. 'harr;' => "\xE2\x86\x94",
  4703. 'hearts;' => "\xE2\x99\xA5",
  4704. 'hellip;' => "\xE2\x80\xA6",
  4705. 'Iacute' => "\xC3\x8D",
  4706. 'iacute' => "\xC3\xAD",
  4707. 'Iacute;' => "\xC3\x8D",
  4708. 'iacute;' => "\xC3\xAD",
  4709. 'Icirc' => "\xC3\x8E",
  4710. 'icirc' => "\xC3\xAE",
  4711. 'Icirc;' => "\xC3\x8E",
  4712. 'icirc;' => "\xC3\xAE",
  4713. 'iexcl' => "\xC2\xA1",
  4714. 'iexcl;' => "\xC2\xA1",
  4715. 'Igrave' => "\xC3\x8C",
  4716. 'igrave' => "\xC3\xAC",
  4717. 'Igrave;' => "\xC3\x8C",
  4718. 'igrave;' => "\xC3\xAC",
  4719. 'image;' => "\xE2\x84\x91",
  4720. 'infin;' => "\xE2\x88\x9E",
  4721. 'int;' => "\xE2\x88\xAB",
  4722. 'Iota;' => "\xCE\x99",
  4723. 'iota;' => "\xCE\xB9",
  4724. 'iquest' => "\xC2\xBF",
  4725. 'iquest;' => "\xC2\xBF",
  4726. 'isin;' => "\xE2\x88\x88",
  4727. 'Iuml' => "\xC3\x8F",
  4728. 'iuml' => "\xC3\xAF",
  4729. 'Iuml;' => "\xC3\x8F",
  4730. 'iuml;' => "\xC3\xAF",
  4731. 'Kappa;' => "\xCE\x9A",
  4732. 'kappa;' => "\xCE\xBA",
  4733. 'Lambda;' => "\xCE\x9B",
  4734. 'lambda;' => "\xCE\xBB",
  4735. 'lang;' => "\xE3\x80\x88",
  4736. 'laquo' => "\xC2\xAB",
  4737. 'laquo;' => "\xC2\xAB",
  4738. 'lArr;' => "\xE2\x87\x90",
  4739. 'larr;' => "\xE2\x86\x90",
  4740. 'lceil;' => "\xE2\x8C\x88",
  4741. 'ldquo;' => "\xE2\x80\x9C",
  4742. 'le;' => "\xE2\x89\xA4",
  4743. 'lfloor;' => "\xE2\x8C\x8A",
  4744. 'lowast;' => "\xE2\x88\x97",
  4745. 'loz;' => "\xE2\x97\x8A",
  4746. 'lrm;' => "\xE2\x80\x8E",
  4747. 'lsaquo;' => "\xE2\x80\xB9",
  4748. 'lsquo;' => "\xE2\x80\x98",
  4749. 'LT' => "\x3C",
  4750. 'lt' => "\x3C",
  4751. 'LT;' => "\x3C",
  4752. 'lt;' => "\x3C",
  4753. 'macr' => "\xC2\xAF",
  4754. 'macr;' => "\xC2\xAF",
  4755. 'mdash;' => "\xE2\x80\x94",
  4756. 'micro' => "\xC2\xB5",
  4757. 'micro;' => "\xC2\xB5",
  4758. 'middot' => "\xC2\xB7",
  4759. 'middot;' => "\xC2\xB7",
  4760. 'minus;' => "\xE2\x88\x92",
  4761. 'Mu;' => "\xCE\x9C",
  4762. 'mu;' => "\xCE\xBC",
  4763. 'nabla;' => "\xE2\x88\x87",
  4764. 'nbsp' => "\xC2\xA0",
  4765. 'nbsp;' => "\xC2\xA0",
  4766. 'ndash;' => "\xE2\x80\x93",
  4767. 'ne;' => "\xE2\x89\xA0",
  4768. 'ni;' => "\xE2\x88\x8B",
  4769. 'not' => "\xC2\xAC",
  4770. 'not;' => "\xC2\xAC",
  4771. 'notin;' => "\xE2\x88\x89",
  4772. 'nsub;' => "\xE2\x8A\x84",
  4773. 'Ntilde' => "\xC3\x91",
  4774. 'ntilde' => "\xC3\xB1",
  4775. 'Ntilde;' => "\xC3\x91",
  4776. 'ntilde;' => "\xC3\xB1",
  4777. 'Nu;' => "\xCE\x9D",
  4778. 'nu;' => "\xCE\xBD",
  4779. 'Oacute' => "\xC3\x93",
  4780. 'oacute' => "\xC3\xB3",
  4781. 'Oacute;' => "\xC3\x93",
  4782. 'oacute;' => "\xC3\xB3",
  4783. 'Ocirc' => "\xC3\x94",
  4784. 'ocirc' => "\xC3\xB4",
  4785. 'Ocirc;' => "\xC3\x94",
  4786. 'ocirc;' => "\xC3\xB4",
  4787. 'OElig;' => "\xC5\x92",
  4788. 'oelig;' => "\xC5\x93",
  4789. 'Ograve' => "\xC3\x92",
  4790. 'ograve' => "\xC3\xB2",
  4791. 'Ograve;' => "\xC3\x92",
  4792. 'ograve;' => "\xC3\xB2",
  4793. 'oline;' => "\xE2\x80\xBE",
  4794. 'Omega;' => "\xCE\xA9",
  4795. 'omega;' => "\xCF\x89",
  4796. 'Omicron;' => "\xCE\x9F",
  4797. 'omicron;' => "\xCE\xBF",
  4798. 'oplus;' => "\xE2\x8A\x95",
  4799. 'or;' => "\xE2\x88\xA8",
  4800. 'ordf' => "\xC2\xAA",
  4801. 'ordf;' => "\xC2\xAA",
  4802. 'ordm' => "\xC2\xBA",
  4803. 'ordm;' => "\xC2\xBA",
  4804. 'Oslash' => "\xC3\x98",
  4805. 'oslash' => "\xC3\xB8",
  4806. 'Oslash;' => "\xC3\x98",
  4807. 'oslash;' => "\xC3\xB8",
  4808. 'Otilde' => "\xC3\x95",
  4809. 'otilde' => "\xC3\xB5",
  4810. 'Otilde;' => "\xC3\x95",
  4811. 'otilde;' => "\xC3\xB5",
  4812. 'otimes;' => "\xE2\x8A\x97",
  4813. 'Ouml' => "\xC3\x96",
  4814. 'ouml' => "\xC3\xB6",
  4815. 'Ouml;' => "\xC3\x96",
  4816. 'ouml;' => "\xC3\xB6",
  4817. 'para' => "\xC2\xB6",
  4818. 'para;' => "\xC2\xB6",
  4819. 'part;' => "\xE2\x88\x82",
  4820. 'permil;' => "\xE2\x80\xB0",
  4821. 'perp;' => "\xE2\x8A\xA5",
  4822. 'Phi;' => "\xCE\xA6",
  4823. 'phi;' => "\xCF\x86",
  4824. 'Pi;' => "\xCE\xA0",
  4825. 'pi;' => "\xCF\x80",
  4826. 'piv;' => "\xCF\x96",
  4827. 'plusmn' => "\xC2\xB1",
  4828. 'plusmn;' => "\xC2\xB1",
  4829. 'pound' => "\xC2\xA3",
  4830. 'pound;' => "\xC2\xA3",
  4831. 'Prime;' => "\xE2\x80\xB3",
  4832. 'prime;' => "\xE2\x80\xB2",
  4833. 'prod;' => "\xE2\x88\x8F",
  4834. 'prop;' => "\xE2\x88\x9D",
  4835. 'Psi;' => "\xCE\xA8",
  4836. 'psi;' => "\xCF\x88",
  4837. 'QUOT' => "\x22",
  4838. 'quot' => "\x22",
  4839. 'QUOT;' => "\x22",
  4840. 'quot;' => "\x22",
  4841. 'radic;' => "\xE2\x88\x9A",
  4842. 'rang;' => "\xE3\x80\x89",
  4843. 'raquo' => "\xC2\xBB",
  4844. 'raquo;' => "\xC2\xBB",
  4845. 'rArr;' => "\xE2\x87\x92",
  4846. 'rarr;' => "\xE2\x86\x92",
  4847. 'rceil;' => "\xE2\x8C\x89",
  4848. 'rdquo;' => "\xE2\x80\x9D",
  4849. 'real;' => "\xE2\x84\x9C",
  4850. 'REG' => "\xC2\xAE",
  4851. 'reg' => "\xC2\xAE",
  4852. 'REG;' => "\xC2\xAE",
  4853. 'reg;' => "\xC2\xAE",
  4854. 'rfloor;' => "\xE2\x8C\x8B",
  4855. 'Rho;' => "\xCE\xA1",
  4856. 'rho;' => "\xCF\x81",
  4857. 'rlm;' => "\xE2\x80\x8F",
  4858. 'rsaquo;' => "\xE2\x80\xBA",
  4859. 'rsquo;' => "\xE2\x80\x99",
  4860. 'sbquo;' => "\xE2\x80\x9A",
  4861. 'Scaron;' => "\xC5\xA0",
  4862. 'scaron;' => "\xC5\xA1",
  4863. 'sdot;' => "\xE2\x8B\x85",
  4864. 'sect' => "\xC2\xA7",
  4865. 'sect;' => "\xC2\xA7",
  4866. 'shy' => "\xC2\xAD",
  4867. 'shy;' => "\xC2\xAD",
  4868. 'Sigma;' => "\xCE\xA3",
  4869. 'sigma;' => "\xCF\x83",
  4870. 'sigmaf;' => "\xCF\x82",
  4871. 'sim;' => "\xE2\x88\xBC",
  4872. 'spades;' => "\xE2\x99\xA0",
  4873. 'sub;' => "\xE2\x8A\x82",
  4874. 'sube;' => "\xE2\x8A\x86",
  4875. 'sum;' => "\xE2\x88\x91",
  4876. 'sup;' => "\xE2\x8A\x83",
  4877. 'sup1' => "\xC2\xB9",
  4878. 'sup1;' => "\xC2\xB9",
  4879. 'sup2' => "\xC2\xB2",
  4880. 'sup2;' => "\xC2\xB2",
  4881. 'sup3' => "\xC2\xB3",
  4882. 'sup3;' => "\xC2\xB3",
  4883. 'supe;' => "\xE2\x8A\x87",
  4884. 'szlig' => "\xC3\x9F",
  4885. 'szlig;' => "\xC3\x9F",
  4886. 'Tau;' => "\xCE\xA4",
  4887. 'tau;' => "\xCF\x84",
  4888. 'there4;' => "\xE2\x88\xB4",
  4889. 'Theta;' => "\xCE\x98",
  4890. 'theta;' => "\xCE\xB8",
  4891. 'thetasym;' => "\xCF\x91",
  4892. 'thinsp;' => "\xE2\x80\x89",
  4893. 'THORN' => "\xC3\x9E",
  4894. 'thorn' => "\xC3\xBE",
  4895. 'THORN;' => "\xC3\x9E",
  4896. 'thorn;' => "\xC3\xBE",
  4897. 'tilde;' => "\xCB\x9C",
  4898. 'times' => "\xC3\x97",
  4899. 'times;' => "\xC3\x97",
  4900. 'TRADE;' => "\xE2\x84\xA2",
  4901. 'trade;' => "\xE2\x84\xA2",
  4902. 'Uacute' => "\xC3\x9A",
  4903. 'uacute' => "\xC3\xBA",
  4904. 'Uacute;' => "\xC3\x9A",
  4905. 'uacute;' => "\xC3\xBA",
  4906. 'uArr;' => "\xE2\x87\x91",
  4907. 'uarr;' => "\xE2\x86\x91",
  4908. 'Ucirc' => "\xC3\x9B",
  4909. 'ucirc' => "\xC3\xBB",
  4910. 'Ucirc;' => "\xC3\x9B",
  4911. 'ucirc;' => "\xC3\xBB",
  4912. 'Ugrave' => "\xC3\x99",
  4913. 'ugrave' => "\xC3\xB9",
  4914. 'Ugrave;' => "\xC3\x99",
  4915. 'ugrave;' => "\xC3\xB9",
  4916. 'uml' => "\xC2\xA8",
  4917. 'uml;' => "\xC2\xA8",
  4918. 'upsih;' => "\xCF\x92",
  4919. 'Upsilon;' => "\xCE\xA5",
  4920. 'upsilon;' => "\xCF\x85",
  4921. 'Uuml' => "\xC3\x9C",
  4922. 'uuml' => "\xC3\xBC",
  4923. 'Uuml;' => "\xC3\x9C",
  4924. 'uuml;' => "\xC3\xBC",
  4925. 'weierp;' => "\xE2\x84\x98",
  4926. 'Xi;' => "\xCE\x9E",
  4927. 'xi;' => "\xCE\xBE",
  4928. 'Yacute' => "\xC3\x9D",
  4929. 'yacute' => "\xC3\xBD",
  4930. 'Yacute;' => "\xC3\x9D",
  4931. 'yacute;' => "\xC3\xBD",
  4932. 'yen' => "\xC2\xA5",
  4933. 'yen;' => "\xC2\xA5",
  4934. 'yuml' => "\xC3\xBF",
  4935. 'Yuml;' => "\xC5\xB8",
  4936. 'yuml;' => "\xC3\xBF",
  4937. 'Zeta;' => "\xCE\x96",
  4938. 'zeta;' => "\xCE\xB6",
  4939. 'zwj;' => "\xE2\x80\x8D",
  4940. 'zwnj;' => "\xE2\x80\x8C"
  4941. );
  4942. for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
  4943. {
  4944. $consumed = substr($this->consumed, 1);
  4945. if (isset($entities[$consumed]))
  4946. {
  4947. $match = $consumed;
  4948. }
  4949. }
  4950. if ($match !== null)
  4951. {
  4952. $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
  4953. $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
  4954. }
  4955. break;
  4956. }
  4957. }
  4958. }
  4959. /**
  4960. * Handles everything related to enclosures (including Media RSS and iTunes RSS)
  4961. *
  4962. * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
  4963. *
  4964. * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
  4965. *
  4966. * @package SimplePie
  4967. * @subpackage API
  4968. */
  4969. class SimplePie_Enclosure
  4970. {
  4971. /**
  4972. * @var string
  4973. * @see get_bitrate()
  4974. */
  4975. var $bitrate;
  4976. /**
  4977. * @var array
  4978. * @see get_captions()
  4979. */
  4980. var $captions;
  4981. /**
  4982. * @var array
  4983. * @see get_categories()
  4984. */
  4985. var $categories;
  4986. /**
  4987. * @var int
  4988. * @see get_channels()
  4989. */
  4990. var $channels;
  4991. /**
  4992. * @var SimplePie_Copyright
  4993. * @see get_copyright()
  4994. */
  4995. var $copyright;
  4996. /**
  4997. * @var array
  4998. * @see get_credits()
  4999. */
  5000. var $credits;
  5001. /**
  5002. * @var string
  5003. * @see get_description()
  5004. */
  5005. var $description;
  5006. /**
  5007. * @var int
  5008. * @see get_duration()
  5009. */
  5010. var $duration;
  5011. /**
  5012. * @var string
  5013. * @see get_expression()
  5014. */
  5015. var $expression;
  5016. /**
  5017. * @var string
  5018. * @see get_framerate()
  5019. */
  5020. var $framerate;
  5021. /**
  5022. * @var string
  5023. * @see get_handler()
  5024. */
  5025. var $handler;
  5026. /**
  5027. * @var array
  5028. * @see get_hashes()
  5029. */
  5030. var $hashes;
  5031. /**
  5032. * @var string
  5033. * @see get_height()
  5034. */
  5035. var $height;
  5036. /**
  5037. * @deprecated
  5038. * @var null
  5039. */
  5040. var $javascript;
  5041. /**
  5042. * @var array
  5043. * @see get_keywords()
  5044. */
  5045. var $keywords;
  5046. /**
  5047. * @var string
  5048. * @see get_language()
  5049. */
  5050. var $lang;
  5051. /**
  5052. * @var string
  5053. * @see get_length()
  5054. */
  5055. var $length;
  5056. /**
  5057. * @var string
  5058. * @see get_link()
  5059. */
  5060. var $link;
  5061. /**
  5062. * @var string
  5063. * @see get_medium()
  5064. */
  5065. var $medium;
  5066. /**
  5067. * @var string
  5068. * @see get_player()
  5069. */
  5070. var $player;
  5071. /**
  5072. * @var array
  5073. * @see get_ratings()
  5074. */
  5075. var $ratings;
  5076. /**
  5077. * @var array
  5078. * @see get_restrictions()
  5079. */
  5080. var $restrictions;
  5081. /**
  5082. * @var string
  5083. * @see get_sampling_rate()
  5084. */
  5085. var $samplingrate;
  5086. /**
  5087. * @var array
  5088. * @see get_thumbnails()
  5089. */
  5090. var $thumbnails;
  5091. /**
  5092. * @var string
  5093. * @see get_title()
  5094. */
  5095. var $title;
  5096. /**
  5097. * @var string
  5098. * @see get_type()
  5099. */
  5100. var $type;
  5101. /**
  5102. * @var string
  5103. * @see get_width()
  5104. */
  5105. var $width;
  5106. /**
  5107. * Constructor, used to input the data
  5108. *
  5109. * For documentation on all the parameters, see the corresponding
  5110. * properties and their accessors
  5111. *
  5112. * @uses idna_convert If available, this will convert an IDN
  5113. */
  5114. 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)
  5115. {
  5116. $this->bitrate = $bitrate;
  5117. $this->captions = $captions;
  5118. $this->categories = $categories;
  5119. $this->channels = $channels;
  5120. $this->copyright = $copyright;
  5121. $this->credits = $credits;
  5122. $this->description = $description;
  5123. $this->duration = $duration;
  5124. $this->expression = $expression;
  5125. $this->framerate = $framerate;
  5126. $this->hashes = $hashes;
  5127. $this->height = $height;
  5128. $this->keywords = $keywords;
  5129. $this->lang = $lang;
  5130. $this->length = $length;
  5131. $this->link = $link;
  5132. $this->medium = $medium;
  5133. $this->player = $player;
  5134. $this->ratings = $ratings;
  5135. $this->restrictions = $restrictions;
  5136. $this->samplingrate = $samplingrate;
  5137. $this->thumbnails = $thumbnails;
  5138. $this->title = $title;
  5139. $this->type = $type;
  5140. $this->width = $width;
  5141. if (class_exists('idna_convert'))
  5142. {
  5143. $idn = new idna_convert();
  5144. $parsed = SimplePie_Misc::parse_url($link);
  5145. $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
  5146. }
  5147. $this->handler = $this->get_handler(); // Needs to load last
  5148. }
  5149. /**
  5150. * String-ified version
  5151. *
  5152. * @return string
  5153. */
  5154. public function __toString()
  5155. {
  5156. // There is no $this->data here
  5157. return md5(serialize($this));
  5158. }
  5159. /**
  5160. * Get the bitrate
  5161. *
  5162. * @return string|null
  5163. */
  5164. public function get_bitrate()
  5165. {
  5166. if ($this->bitrate !== null)
  5167. {
  5168. return $this->bitrate;
  5169. }
  5170. else
  5171. {
  5172. return null;
  5173. }
  5174. }
  5175. /**
  5176. * Get a single caption
  5177. *
  5178. * @param int $key
  5179. * @return SimplePie_Caption|null
  5180. */
  5181. public function get_caption($key = 0)
  5182. {
  5183. $captions = $this->get_captions();
  5184. if (isset($captions[$key]))
  5185. {
  5186. return $captions[$key];
  5187. }
  5188. else
  5189. {
  5190. return null;
  5191. }
  5192. }
  5193. /**
  5194. * Get all captions
  5195. *
  5196. * @return array|null Array of {@see SimplePie_Caption} objects
  5197. */
  5198. public function get_captions()
  5199. {
  5200. if ($this->captions !== null)
  5201. {
  5202. return $this->captions;
  5203. }
  5204. else
  5205. {
  5206. return null;
  5207. }
  5208. }
  5209. /**
  5210. * Get a single category
  5211. *
  5212. * @param int $key
  5213. * @return SimplePie_Category|null
  5214. */
  5215. public function get_category($key = 0)
  5216. {
  5217. $categories = $this->get_categories();
  5218. if (isset($categories[$key]))
  5219. {
  5220. return $categories[$key];
  5221. }
  5222. else
  5223. {
  5224. return null;
  5225. }
  5226. }
  5227. /**
  5228. * Get all categories
  5229. *
  5230. * @return array|null Array of {@see SimplePie_Category} objects
  5231. */
  5232. public function get_categories()
  5233. {
  5234. if ($this->categories !== null)
  5235. {
  5236. return $this->categories;
  5237. }
  5238. else
  5239. {
  5240. return null;
  5241. }
  5242. }
  5243. /**
  5244. * Get the number of audio channels
  5245. *
  5246. * @return int|null
  5247. */
  5248. public function get_channels()
  5249. {
  5250. if ($this->channels !== null)
  5251. {
  5252. return $this->channels;
  5253. }
  5254. else
  5255. {
  5256. return null;
  5257. }
  5258. }
  5259. /**
  5260. * Get the copyright information
  5261. *
  5262. * @return SimplePie_Copyright|null
  5263. */
  5264. public function get_copyright()
  5265. {
  5266. if ($this->copyright !== null)
  5267. {
  5268. return $this->copyright;
  5269. }
  5270. else
  5271. {
  5272. return null;
  5273. }
  5274. }
  5275. /**
  5276. * Get a single credit
  5277. *
  5278. * @param int $key
  5279. * @return SimplePie_Credit|null
  5280. */
  5281. public function get_credit($key = 0)
  5282. {
  5283. $credits = $this->get_credits();
  5284. if (isset($credits[$key]))
  5285. {
  5286. return $credits[$key];
  5287. }
  5288. else
  5289. {
  5290. return null;
  5291. }
  5292. }
  5293. /**
  5294. * Get all credits
  5295. *
  5296. * @return array|null Array of {@see SimplePie_Credit} objects
  5297. */
  5298. public function get_credits()
  5299. {
  5300. if ($this->credits !== null)
  5301. {
  5302. return $this->credits;
  5303. }
  5304. else
  5305. {
  5306. return null;
  5307. }
  5308. }
  5309. /**
  5310. * Get the description of the enclosure
  5311. *
  5312. * @return string|null
  5313. */
  5314. public function get_description()
  5315. {
  5316. if ($this->description !== null)
  5317. {
  5318. return $this->description;
  5319. }
  5320. else
  5321. {
  5322. return null;
  5323. }
  5324. }
  5325. /**
  5326. * Get the duration of the enclosure
  5327. *
  5328. * @param string $convert Convert seconds into hh:mm:ss
  5329. * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
  5330. */
  5331. public function get_duration($convert = false)
  5332. {
  5333. if ($this->duration !== null)
  5334. {
  5335. if ($convert)
  5336. {
  5337. $time = SimplePie_Misc::time_hms($this->duration);
  5338. return $time;
  5339. }
  5340. else
  5341. {
  5342. return $this->duration;
  5343. }
  5344. }
  5345. else
  5346. {
  5347. return null;
  5348. }
  5349. }
  5350. /**
  5351. * Get the expression
  5352. *
  5353. * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
  5354. */
  5355. public function get_expression()
  5356. {
  5357. if ($this->expression !== null)
  5358. {
  5359. return $this->expression;
  5360. }
  5361. else
  5362. {
  5363. return 'full';
  5364. }
  5365. }
  5366. /**
  5367. * Get the file extension
  5368. *
  5369. * @return string|null
  5370. */
  5371. public function get_extension()
  5372. {
  5373. if ($this->link !== null)
  5374. {
  5375. $url = SimplePie_Misc::parse_url($this->link);
  5376. if ($url['path'] !== '')
  5377. {
  5378. return pathinfo($url['path'], PATHINFO_EXTENSION);
  5379. }
  5380. }
  5381. return null;
  5382. }
  5383. /**
  5384. * Get the framerate (in frames-per-second)
  5385. *
  5386. * @return string|null
  5387. */
  5388. public function get_framerate()
  5389. {
  5390. if ($this->framerate !== null)
  5391. {
  5392. return $this->framerate;
  5393. }
  5394. else
  5395. {
  5396. return null;
  5397. }
  5398. }
  5399. /**
  5400. * Get the preferred handler
  5401. *
  5402. * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
  5403. */
  5404. public function get_handler()
  5405. {
  5406. return $this->get_real_type(true);
  5407. }
  5408. /**
  5409. * Get a single hash
  5410. *
  5411. * @link http://www.rssboard.org/media-rss#media-hash
  5412. * @param int $key
  5413. * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
  5414. */
  5415. public function get_hash($key = 0)
  5416. {
  5417. $hashes = $this->get_hashes();
  5418. if (isset($hashes[$key]))
  5419. {
  5420. return $hashes[$key];
  5421. }
  5422. else
  5423. {
  5424. return null;
  5425. }
  5426. }
  5427. /**
  5428. * Get all credits
  5429. *
  5430. * @return array|null Array of strings, see {@see get_hash()}
  5431. */
  5432. public function get_hashes()
  5433. {
  5434. if ($this->hashes !== null)
  5435. {
  5436. return $this->hashes;
  5437. }
  5438. else
  5439. {
  5440. return null;
  5441. }
  5442. }
  5443. /**
  5444. * Get the height
  5445. *
  5446. * @return string|null
  5447. */
  5448. public function get_height()
  5449. {
  5450. if ($this->height !== null)
  5451. {
  5452. return $this->height;
  5453. }
  5454. else
  5455. {
  5456. return null;
  5457. }
  5458. }
  5459. /**
  5460. * Get the language
  5461. *
  5462. * @link http://tools.ietf.org/html/rfc3066
  5463. * @return string|null Language code as per RFC 3066
  5464. */
  5465. public function get_language()
  5466. {
  5467. if ($this->lang !== null)
  5468. {
  5469. return $this->lang;
  5470. }
  5471. else
  5472. {
  5473. return null;
  5474. }
  5475. }
  5476. /**
  5477. * Get a single keyword
  5478. *
  5479. * @param int $key
  5480. * @return string|null
  5481. */
  5482. public function get_keyword($key = 0)
  5483. {
  5484. $keywords = $this->get_keywords();
  5485. if (isset($keywords[$key]))
  5486. {
  5487. return $keywords[$key];
  5488. }
  5489. else
  5490. {
  5491. return null;
  5492. }
  5493. }
  5494. /**
  5495. * Get all keywords
  5496. *
  5497. * @return array|null Array of strings
  5498. */
  5499. public function get_keywords()
  5500. {
  5501. if ($this->keywords !== null)
  5502. {
  5503. return $this->keywords;
  5504. }
  5505. else
  5506. {
  5507. return null;
  5508. }
  5509. }
  5510. /**
  5511. * Get length
  5512. *
  5513. * @return float Length in bytes
  5514. */
  5515. public function get_length()
  5516. {
  5517. if ($this->length !== null)
  5518. {
  5519. return $this->length;
  5520. }
  5521. else
  5522. {
  5523. return null;
  5524. }
  5525. }
  5526. /**
  5527. * Get the URL
  5528. *
  5529. * @return string|null
  5530. */
  5531. public function get_link()
  5532. {
  5533. if ($this->link !== null)
  5534. {
  5535. return urldecode($this->link);
  5536. }
  5537. else
  5538. {
  5539. return null;
  5540. }
  5541. }
  5542. /**
  5543. * Get the medium
  5544. *
  5545. * @link http://www.rssboard.org/media-rss#media-content
  5546. * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
  5547. */
  5548. public function get_medium()
  5549. {
  5550. if ($this->medium !== null)
  5551. {
  5552. return $this->medium;
  5553. }
  5554. else
  5555. {
  5556. return null;
  5557. }
  5558. }
  5559. /**
  5560. * Get the player URL
  5561. *
  5562. * Typically the same as {@see get_permalink()}
  5563. * @return string|null Player URL
  5564. */
  5565. public function get_player()
  5566. {
  5567. if ($this->player !== null)
  5568. {
  5569. return $this->player;
  5570. }
  5571. else
  5572. {
  5573. return null;
  5574. }
  5575. }
  5576. /**
  5577. * Get a single rating
  5578. *
  5579. * @param int $key
  5580. * @return SimplePie_Rating|null
  5581. */
  5582. public function get_rating($key = 0)
  5583. {
  5584. $ratings = $this->get_ratings();
  5585. if (isset($ratings[$key]))
  5586. {
  5587. return $ratings[$key];
  5588. }
  5589. else
  5590. {
  5591. return null;
  5592. }
  5593. }
  5594. /**
  5595. * Get all ratings
  5596. *
  5597. * @return array|null Array of {@see SimplePie_Rating} objects
  5598. */
  5599. public function get_ratings()
  5600. {
  5601. if ($this->ratings !== null)
  5602. {
  5603. return $this->ratings;
  5604. }
  5605. else
  5606. {
  5607. return null;
  5608. }
  5609. }
  5610. /**
  5611. * Get a single restriction
  5612. *
  5613. * @param int $key
  5614. * @return SimplePie_Restriction|null
  5615. */
  5616. public function get_restriction($key = 0)
  5617. {
  5618. $restrictions = $this->get_restrictions();
  5619. if (isset($restrictions[$key]))
  5620. {
  5621. return $restrictions[$key];
  5622. }
  5623. else
  5624. {
  5625. return null;
  5626. }
  5627. }
  5628. /**
  5629. * Get all restrictions
  5630. *
  5631. * @return array|null Array of {@see SimplePie_Restriction} objects
  5632. */
  5633. public function get_restrictions()
  5634. {
  5635. if ($this->restrictions !== null)
  5636. {
  5637. return $this->restrictions;
  5638. }
  5639. else
  5640. {
  5641. return null;
  5642. }
  5643. }
  5644. /**
  5645. * Get the sampling rate (in kHz)
  5646. *
  5647. * @return string|null
  5648. */
  5649. public function get_sampling_rate()
  5650. {
  5651. if ($this->samplingrate !== null)
  5652. {
  5653. return $this->samplingrate;
  5654. }
  5655. else
  5656. {
  5657. return null;
  5658. }
  5659. }
  5660. /**
  5661. * Get the file size (in MiB)
  5662. *
  5663. * @return float|null File size in mebibytes (1048 bytes)
  5664. */
  5665. public function get_size()
  5666. {
  5667. $length = $this->get_length();
  5668. if ($length !== null)
  5669. {
  5670. return round($length/1048576, 2);
  5671. }
  5672. else
  5673. {
  5674. return null;
  5675. }
  5676. }
  5677. /**
  5678. * Get a single thumbnail
  5679. *
  5680. * @param int $key
  5681. * @return string|null Thumbnail URL
  5682. */
  5683. public function get_thumbnail($key = 0)
  5684. {
  5685. $thumbnails = $this->get_thumbnails();
  5686. if (isset($thumbnails[$key]))
  5687. {
  5688. return $thumbnails[$key];
  5689. }
  5690. else
  5691. {
  5692. return null;
  5693. }
  5694. }
  5695. /**
  5696. * Get all thumbnails
  5697. *
  5698. * @return array|null Array of thumbnail URLs
  5699. */
  5700. public function get_thumbnails()
  5701. {
  5702. if ($this->thumbnails !== null)
  5703. {
  5704. return $this->thumbnails;
  5705. }
  5706. else
  5707. {
  5708. return null;
  5709. }
  5710. }
  5711. /**
  5712. * Get the title
  5713. *
  5714. * @return string|null
  5715. */
  5716. public function get_title()
  5717. {
  5718. if ($this->title !== null)
  5719. {
  5720. return $this->title;
  5721. }
  5722. else
  5723. {
  5724. return null;
  5725. }
  5726. }
  5727. /**
  5728. * Get mimetype of the enclosure
  5729. *
  5730. * @see get_real_type()
  5731. * @return string|null MIME type
  5732. */
  5733. public function get_type()
  5734. {
  5735. if ($this->type !== null)
  5736. {
  5737. return $this->type;
  5738. }
  5739. else
  5740. {
  5741. return null;
  5742. }
  5743. }
  5744. /**
  5745. * Get the width
  5746. *
  5747. * @return string|null
  5748. */
  5749. public function get_width()
  5750. {
  5751. if ($this->width !== null)
  5752. {
  5753. return $this->width;
  5754. }
  5755. else
  5756. {
  5757. return null;
  5758. }
  5759. }
  5760. /**
  5761. * Embed the enclosure using `<embed>`
  5762. *
  5763. * @deprecated Use the second parameter to {@see embed} instead
  5764. *
  5765. * @param array|string $options See first paramter to {@see embed}
  5766. * @return string HTML string to output
  5767. */
  5768. public function native_embed($options='')
  5769. {
  5770. return $this->embed($options, true);
  5771. }
  5772. /**
  5773. * Embed the enclosure using Javascript
  5774. *
  5775. * `$options` is an array or comma-separated key:value string, with the
  5776. * following properties:
  5777. *
  5778. * - `alt` (string): Alternate content for when an end-user does not have
  5779. * the appropriate handler installed or when a file type is
  5780. * unsupported. Can be any text or HTML. Defaults to blank.
  5781. * - `altclass` (string): If a file type is unsupported, the end-user will
  5782. * see the alt text (above) linked directly to the content. That link
  5783. * will have this value as its class name. Defaults to blank.
  5784. * - `audio` (string): This is an image that should be used as a
  5785. * placeholder for audio files before they're loaded (QuickTime-only).
  5786. * Can be any relative or absolute URL. Defaults to blank.
  5787. * - `bgcolor` (string): The background color for the media, if not
  5788. * already transparent. Defaults to `#ffffff`.
  5789. * - `height` (integer): The height of the embedded media. Accepts any
  5790. * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
  5791. * and it is recommended that you use this default.
  5792. * - `loop` (boolean): Do you want the media to loop when its done?
  5793. * Defaults to `false`.
  5794. * - `mediaplayer` (string): The location of the included
  5795. * `mediaplayer.swf` file. This allows for the playback of Flash Video
  5796. * (`.flv`) files, and is the default handler for non-Odeo MP3's.
  5797. * Defaults to blank.
  5798. * - `video` (string): This is an image that should be used as a
  5799. * placeholder for video files before they're loaded (QuickTime-only).
  5800. * Can be any relative or absolute URL. Defaults to blank.
  5801. * - `width` (integer): The width of the embedded media. Accepts any
  5802. * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
  5803. * and it is recommended that you use this default.
  5804. * - `widescreen` (boolean): Is the enclosure widescreen or standard?
  5805. * This applies only to video enclosures, and will automatically resize
  5806. * the content appropriately. Defaults to `false`, implying 4:3 mode.
  5807. *
  5808. * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
  5809. * will default to 480x360 video resolution. Widescreen (16:9) mode with
  5810. * `width` and `height` set to `auto` will default to 480x270 video resolution.
  5811. *
  5812. * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
  5813. * @param array|string $options Comma-separated key:value list, or array
  5814. * @param bool $native Use `<embed>`
  5815. * @return string HTML string to output
  5816. */
  5817. public function embed($options = '', $native = false)
  5818. {
  5819. // Set up defaults
  5820. $audio = '';
  5821. $video = '';
  5822. $alt = '';
  5823. $altclass = '';
  5824. $loop = 'false';
  5825. $width = 'auto';
  5826. $height = 'auto';
  5827. $bgcolor = '#ffffff';
  5828. $mediaplayer = '';
  5829. $widescreen = false;
  5830. $handler = $this->get_handler();
  5831. $type = $this->get_real_type();
  5832. // Process options and reassign values as necessary
  5833. if (is_array($options))
  5834. {
  5835. extract($options);
  5836. }
  5837. else
  5838. {
  5839. $options = explode(',', $options);
  5840. foreach($options as $option)
  5841. {
  5842. $opt = explode(':', $option, 2);
  5843. if (isset($opt[0], $opt[1]))
  5844. {
  5845. $opt[0] = trim($opt[0]);
  5846. $opt[1] = trim($opt[1]);
  5847. switch ($opt[0])
  5848. {
  5849. case 'audio':
  5850. $audio = $opt[1];
  5851. break;
  5852. case 'video':
  5853. $video = $opt[1];
  5854. break;
  5855. case 'alt':
  5856. $alt = $opt[1];
  5857. break;
  5858. case 'altclass':
  5859. $altclass = $opt[1];
  5860. break;
  5861. case 'loop':
  5862. $loop = $opt[1];
  5863. break;
  5864. case 'width':
  5865. $width = $opt[1];
  5866. break;
  5867. case 'height':
  5868. $height = $opt[1];
  5869. break;
  5870. case 'bgcolor':
  5871. $bgcolor = $opt[1];
  5872. break;
  5873. case 'mediaplayer':
  5874. $mediaplayer = $opt[1];
  5875. break;
  5876. case 'widescreen':
  5877. $widescreen = $opt[1];
  5878. break;
  5879. }
  5880. }
  5881. }
  5882. }
  5883. $mime = explode('/', $type, 2);
  5884. $mime = $mime[0];
  5885. // Process values for 'auto'
  5886. if ($width === 'auto')
  5887. {
  5888. if ($mime === 'video')
  5889. {
  5890. if ($height === 'auto')
  5891. {
  5892. $width = 480;
  5893. }
  5894. elseif ($widescreen)
  5895. {
  5896. $width = round((intval($height)/9)*16);
  5897. }
  5898. else
  5899. {
  5900. $width = round((intval($height)/3)*4);
  5901. }
  5902. }
  5903. else
  5904. {
  5905. $width = '100%';
  5906. }
  5907. }
  5908. if ($height === 'auto')
  5909. {
  5910. if ($mime === 'audio')
  5911. {
  5912. $height = 0;
  5913. }
  5914. elseif ($mime === 'video')
  5915. {
  5916. if ($width === 'auto')
  5917. {
  5918. if ($widescreen)
  5919. {
  5920. $height = 270;
  5921. }
  5922. else
  5923. {
  5924. $height = 360;
  5925. }
  5926. }
  5927. elseif ($widescreen)
  5928. {
  5929. $height = round((intval($width)/16)*9);
  5930. }
  5931. else
  5932. {
  5933. $height = round((intval($width)/4)*3);
  5934. }
  5935. }
  5936. else
  5937. {
  5938. $height = 376;
  5939. }
  5940. }
  5941. elseif ($mime === 'audio')
  5942. {
  5943. $height = 0;
  5944. }
  5945. // Set proper placeholder value
  5946. if ($mime === 'audio')
  5947. {
  5948. $placeholder = $audio;
  5949. }
  5950. elseif ($mime === 'video')
  5951. {
  5952. $placeholder = $video;
  5953. }
  5954. $embed = '';
  5955. // Flash
  5956. if ($handler === 'flash')
  5957. {
  5958. if ($native)
  5959. {
  5960. $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>";
  5961. }
  5962. else
  5963. {
  5964. $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
  5965. }
  5966. }
  5967. // Flash Media Player file types.
  5968. // Preferred handler for MP3 file types.
  5969. elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
  5970. {
  5971. $height += 20;
  5972. if ($native)
  5973. {
  5974. $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>";
  5975. }
  5976. else
  5977. {
  5978. $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
  5979. }
  5980. }
  5981. // QuickTime 7 file types. Need to test with QuickTime 6.
  5982. // Only handle MP3's if the Flash Media Player is not present.
  5983. elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
  5984. {
  5985. $height += 16;
  5986. if ($native)
  5987. {
  5988. if ($placeholder !== '')
  5989. {
  5990. $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>";
  5991. }
  5992. else
  5993. {
  5994. $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>";
  5995. }
  5996. }
  5997. else
  5998. {
  5999. $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
  6000. }
  6001. }
  6002. // Windows Media
  6003. elseif ($handler === 'wmedia')
  6004. {
  6005. $height += 45;
  6006. if ($native)
  6007. {
  6008. $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>";
  6009. }
  6010. else
  6011. {
  6012. $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
  6013. }
  6014. }
  6015. // Everything else
  6016. else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
  6017. return $embed;
  6018. }
  6019. /**
  6020. * Get the real media type
  6021. *
  6022. * Often, feeds lie to us, necessitating a bit of deeper inspection. This
  6023. * converts types to their canonical representations based on the file
  6024. * extension
  6025. *
  6026. * @see get_type()
  6027. * @param bool $find_handler Internal use only, use {@see get_handler()} instead
  6028. * @return string MIME type
  6029. */
  6030. public function get_real_type($find_handler = false)
  6031. {
  6032. // Mime-types by handler.
  6033. $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
  6034. $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
  6035. $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
  6036. $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
  6037. $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
  6038. if ($this->get_type() !== null)
  6039. {
  6040. $type = strtolower($this->type);
  6041. }
  6042. else
  6043. {
  6044. $type = null;
  6045. }
  6046. // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
  6047. if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
  6048. {
  6049. switch (strtolower($this->get_extension()))
  6050. {
  6051. // Audio mime-types
  6052. case 'aac':
  6053. case 'adts':
  6054. $type = 'audio/acc';
  6055. break;
  6056. case 'aif':
  6057. case 'aifc':
  6058. case 'aiff':
  6059. case 'cdda':
  6060. $type = 'audio/aiff';
  6061. break;
  6062. case 'bwf':
  6063. $type = 'audio/wav';
  6064. break;
  6065. case 'kar':
  6066. case 'mid':
  6067. case 'midi':
  6068. case 'smf':
  6069. $type = 'audio/midi';
  6070. break;
  6071. case 'm4a':
  6072. $type = 'audio/x-m4a';
  6073. break;
  6074. case 'mp3':
  6075. case 'swa':
  6076. $type = 'audio/mp3';
  6077. break;
  6078. case 'wav':
  6079. $type = 'audio/wav';
  6080. break;
  6081. case 'wax':
  6082. $type = 'audio/x-ms-wax';
  6083. break;
  6084. case 'wma':
  6085. $type = 'audio/x-ms-wma';
  6086. break;
  6087. // Video mime-types
  6088. case '3gp':
  6089. case '3gpp':
  6090. $type = 'video/3gpp';
  6091. break;
  6092. case '3g2':
  6093. case '3gp2':
  6094. $type = 'video/3gpp2';
  6095. break;
  6096. case 'asf':
  6097. $type = 'video/x-ms-asf';
  6098. break;
  6099. case 'flv':
  6100. $type = 'video/x-flv';
  6101. break;
  6102. case 'm1a':
  6103. case 'm1s':
  6104. case 'm1v':
  6105. case 'm15':
  6106. case 'm75':
  6107. case 'mp2':
  6108. case 'mpa':
  6109. case 'mpeg':
  6110. case 'mpg':
  6111. case 'mpm':
  6112. case 'mpv':
  6113. $type = 'video/mpeg';
  6114. break;
  6115. case 'm4v':
  6116. $type = 'video/x-m4v';
  6117. break;
  6118. case 'mov':
  6119. case 'qt':
  6120. $type = 'video/quicktime';
  6121. break;
  6122. case 'mp4':
  6123. case 'mpg4':
  6124. $type = 'video/mp4';
  6125. break;
  6126. case 'sdv':
  6127. $type = 'video/sd-video';
  6128. break;
  6129. case 'wm':
  6130. $type = 'video/x-ms-wm';
  6131. break;
  6132. case 'wmv':
  6133. $type = 'video/x-ms-wmv';
  6134. break;
  6135. case 'wvx':
  6136. $type = 'video/x-ms-wvx';
  6137. break;
  6138. // Flash mime-types
  6139. case 'spl':
  6140. $type = 'application/futuresplash';
  6141. break;
  6142. case 'swf':
  6143. $type = 'application/x-shockwave-flash';
  6144. break;
  6145. }
  6146. }
  6147. if ($find_handler)
  6148. {
  6149. if (in_array($type, $types_flash))
  6150. {
  6151. return 'flash';
  6152. }
  6153. elseif (in_array($type, $types_fmedia))
  6154. {
  6155. return 'fmedia';
  6156. }
  6157. elseif (in_array($type, $types_quicktime))
  6158. {
  6159. return 'quicktime';
  6160. }
  6161. elseif (in_array($type, $types_wmedia))
  6162. {
  6163. return 'wmedia';
  6164. }
  6165. elseif (in_array($type, $types_mp3))
  6166. {
  6167. return 'mp3';
  6168. }
  6169. else
  6170. {
  6171. return null;
  6172. }
  6173. }
  6174. else
  6175. {
  6176. return $type;
  6177. }
  6178. }
  6179. }
  6180. /**
  6181. * Used for fetching remote files and reading local files
  6182. *
  6183. * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
  6184. *
  6185. * This class can be overloaded with {@see SimplePie::set_file_class()}
  6186. *
  6187. * @package SimplePie
  6188. * @subpackage HTTP
  6189. * @todo Move to properly supporting RFC2616 (HTTP/1.1)
  6190. */
  6191. class SimplePie_File
  6192. {
  6193. var $url;
  6194. var $useragent;
  6195. var $success = true;
  6196. var $headers = array();
  6197. var $body;
  6198. var $status_code;
  6199. var $redirects = 0;
  6200. var $error;
  6201. var $method = SIMPLEPIE_FILE_SOURCE_NONE;
  6202. public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
  6203. {
  6204. if (class_exists('idna_convert'))
  6205. {
  6206. $idn = new idna_convert();
  6207. $parsed = SimplePie_Misc::parse_url($url);
  6208. $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
  6209. }
  6210. $this->url = $url;
  6211. $this->useragent = $useragent;
  6212. if (preg_match('/^http(s)?:\/\//i', $url))
  6213. {
  6214. if ($useragent === null)
  6215. {
  6216. $useragent = ini_get('user_agent');
  6217. $this->useragent = $useragent;
  6218. }
  6219. if (!is_array($headers))
  6220. {
  6221. $headers = array();
  6222. }
  6223. if (!$force_fsockopen && function_exists('curl_exec'))
  6224. {
  6225. $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
  6226. $fp = curl_init();
  6227. $headers2 = array();
  6228. foreach ($headers as $key => $value)
  6229. {
  6230. $headers2[] = "$key: $value";
  6231. }
  6232. if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
  6233. {
  6234. curl_setopt($fp, CURLOPT_ENCODING, '');
  6235. }
  6236. curl_setopt($fp, CURLOPT_URL, $url);
  6237. curl_setopt($fp, CURLOPT_HEADER, 1);
  6238. curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
  6239. curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
  6240. curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
  6241. curl_setopt($fp, CURLOPT_REFERER, $url);
  6242. curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
  6243. curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
  6244. if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
  6245. {
  6246. curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
  6247. curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
  6248. }
  6249. $this->headers = curl_exec($fp);
  6250. if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
  6251. {
  6252. curl_setopt($fp, CURLOPT_ENCODING, 'none');
  6253. $this->headers = curl_exec($fp);
  6254. }
  6255. if (curl_errno($fp))
  6256. {
  6257. $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
  6258. $this->success = false;
  6259. }
  6260. else
  6261. {
  6262. $info = curl_getinfo($fp);
  6263. curl_close($fp);
  6264. $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
  6265. $this->headers = array_pop($this->headers);
  6266. $parser = new SimplePie_HTTP_Parser($this->headers);
  6267. if ($parser->parse())
  6268. {
  6269. $this->headers = $parser->headers;
  6270. $this->body = $parser->body;
  6271. $this->status_code = $parser->status_code;
  6272. 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)
  6273. {
  6274. $this->redirects++;
  6275. $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
  6276. return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
  6277. }
  6278. }
  6279. }
  6280. }
  6281. else
  6282. {
  6283. $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
  6284. $url_parts = parse_url($url);
  6285. $socket_host = $url_parts['host'];
  6286. if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
  6287. {
  6288. $socket_host = "ssl://$url_parts[host]";
  6289. $url_parts['port'] = 443;
  6290. }
  6291. if (!isset($url_parts['port']))
  6292. {
  6293. $url_parts['port'] = 80;
  6294. }
  6295. $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
  6296. if (!$fp)
  6297. {
  6298. $this->error = 'fsockopen error: ' . $errstr;
  6299. $this->success = false;
  6300. }
  6301. else
  6302. {
  6303. stream_set_timeout($fp, $timeout);
  6304. if (isset($url_parts['path']))
  6305. {
  6306. if (isset($url_parts['query']))
  6307. {
  6308. $get = "$url_parts[path]?$url_parts[query]";
  6309. }
  6310. else
  6311. {
  6312. $get = $url_parts['path'];
  6313. }
  6314. }
  6315. else
  6316. {
  6317. $get = '/';
  6318. }
  6319. $out = "GET $get HTTP/1.1\r\n";
  6320. $out .= "Host: $url_parts[host]\r\n";
  6321. $out .= "User-Agent: $useragent\r\n";
  6322. if (extension_loaded('zlib'))
  6323. {
  6324. $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
  6325. }
  6326. if (isset($url_parts['user']) && isset($url_parts['pass']))
  6327. {
  6328. $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
  6329. }
  6330. foreach ($headers as $key => $value)
  6331. {
  6332. $out .= "$key: $value\r\n";
  6333. }
  6334. $out .= "Connection: Close\r\n\r\n";
  6335. fwrite($fp, $out);
  6336. $info = stream_get_meta_data($fp);
  6337. $this->headers = '';
  6338. while (!$info['eof'] && !$info['timed_out'])
  6339. {
  6340. $this->headers .= fread($fp, 1160);
  6341. $info = stream_get_meta_data($fp);
  6342. }
  6343. if (!$info['timed_out'])
  6344. {
  6345. $parser = new SimplePie_HTTP_Parser($this->headers);
  6346. if ($parser->parse())
  6347. {
  6348. $this->headers = $parser->headers;
  6349. $this->body = $parser->body;
  6350. $this->status_code = $parser->status_code;
  6351. 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)
  6352. {
  6353. $this->redirects++;
  6354. $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
  6355. return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
  6356. }
  6357. if (isset($this->headers['content-encoding']))
  6358. {
  6359. // Hey, we act dumb elsewhere, so let's do that here too
  6360. switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
  6361. {
  6362. case 'gzip':
  6363. case 'x-gzip':
  6364. $decoder = new SimplePie_gzdecode($this->body);
  6365. if (!$decoder->parse())
  6366. {
  6367. $this->error = 'Unable to decode HTTP "gzip" stream';
  6368. $this->success = false;
  6369. }
  6370. else
  6371. {
  6372. $this->body = $decoder->data;
  6373. }
  6374. break;
  6375. case 'deflate':
  6376. if (($decompressed = gzinflate($this->body)) !== false)
  6377. {
  6378. $this->body = $decompressed;
  6379. }
  6380. else if (($decompressed = gzuncompress($this->body)) !== false)
  6381. {
  6382. $this->body = $decompressed;
  6383. }
  6384. else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
  6385. {
  6386. $this->body = $decompressed;
  6387. }
  6388. else
  6389. {
  6390. $this->error = 'Unable to decode HTTP "deflate" stream';
  6391. $this->success = false;
  6392. }
  6393. break;
  6394. default:
  6395. $this->error = 'Unknown content coding';
  6396. $this->success = false;
  6397. }
  6398. }
  6399. }
  6400. }
  6401. else
  6402. {
  6403. $this->error = 'fsocket timed out';
  6404. $this->success = false;
  6405. }
  6406. fclose($fp);
  6407. }
  6408. }
  6409. }
  6410. else
  6411. {
  6412. $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
  6413. if (!$this->body = file_get_contents($url))
  6414. {
  6415. $this->error = 'file_get_contents could not read the file';
  6416. $this->success = false;
  6417. }
  6418. }
  6419. }
  6420. }
  6421. /**
  6422. * Decode 'gzip' encoded HTTP data
  6423. *
  6424. * @package SimplePie
  6425. * @subpackage HTTP
  6426. * @link http://www.gzip.org/format.txt
  6427. */
  6428. class SimplePie_gzdecode
  6429. {
  6430. /**
  6431. * Compressed data
  6432. *
  6433. * @access private
  6434. * @var string
  6435. * @see gzdecode::$data
  6436. */
  6437. var $compressed_data;
  6438. /**
  6439. * Size of compressed data
  6440. *
  6441. * @access private
  6442. * @var int
  6443. */
  6444. var $compressed_size;
  6445. /**
  6446. * Minimum size of a valid gzip string
  6447. *
  6448. * @access private
  6449. * @var int
  6450. */
  6451. var $min_compressed_size = 18;
  6452. /**
  6453. * Current position of pointer
  6454. *
  6455. * @access private
  6456. * @var int
  6457. */
  6458. var $position = 0;
  6459. /**
  6460. * Flags (FLG)
  6461. *
  6462. * @access private
  6463. * @var int
  6464. */
  6465. var $flags;
  6466. /**
  6467. * Uncompressed data
  6468. *
  6469. * @access public
  6470. * @see gzdecode::$compressed_data
  6471. * @var string
  6472. */
  6473. var $data;
  6474. /**
  6475. * Modified time
  6476. *
  6477. * @access public
  6478. * @var int
  6479. */
  6480. var $MTIME;
  6481. /**
  6482. * Extra Flags
  6483. *
  6484. * @access public
  6485. * @var int
  6486. */
  6487. var $XFL;
  6488. /**
  6489. * Operating System
  6490. *
  6491. * @access public
  6492. * @var int
  6493. */
  6494. var $OS;
  6495. /**
  6496. * Subfield ID 1
  6497. *
  6498. * @access public
  6499. * @see gzdecode::$extra_field
  6500. * @see gzdecode::$SI2
  6501. * @var string
  6502. */
  6503. var $SI1;
  6504. /**
  6505. * Subfield ID 2
  6506. *
  6507. * @access public
  6508. * @see gzdecode::$extra_field
  6509. * @see gzdecode::$SI1
  6510. * @var string
  6511. */
  6512. var $SI2;
  6513. /**
  6514. * Extra field content
  6515. *
  6516. * @access public
  6517. * @see gzdecode::$SI1
  6518. * @see gzdecode::$SI2
  6519. * @var string
  6520. */
  6521. var $extra_field;
  6522. /**
  6523. * Original filename
  6524. *
  6525. * @access public
  6526. * @var string
  6527. */
  6528. var $filename;
  6529. /**
  6530. * Human readable comment
  6531. *
  6532. * @access public
  6533. * @var string
  6534. */
  6535. var $comment;
  6536. /**
  6537. * Don't allow anything to be set
  6538. *
  6539. * @param string $name
  6540. * @param mixed $value
  6541. */
  6542. public function __set($name, $value)
  6543. {
  6544. trigger_error("Cannot write property $name", E_USER_ERROR);
  6545. }
  6546. /**
  6547. * Set the compressed string and related properties
  6548. *
  6549. * @param string $data
  6550. */
  6551. public function __construct($data)
  6552. {
  6553. $this->compressed_data = $data;
  6554. $this->compressed_size = strlen($data);
  6555. }
  6556. /**
  6557. * Decode the GZIP stream
  6558. *
  6559. * @return bool Successfulness
  6560. */
  6561. public function parse()
  6562. {
  6563. if ($this->compressed_size >= $this->min_compressed_size)
  6564. {
  6565. // Check ID1, ID2, and CM
  6566. if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
  6567. {
  6568. return false;
  6569. }
  6570. // Get the FLG (FLaGs)
  6571. $this->flags = ord($this->compressed_data[3]);
  6572. // FLG bits above (1 << 4) are reserved
  6573. if ($this->flags > 0x1F)
  6574. {
  6575. return false;
  6576. }
  6577. // Advance the pointer after the above
  6578. $this->position += 4;
  6579. // MTIME
  6580. $mtime = substr($this->compressed_data, $this->position, 4);
  6581. // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
  6582. if (current(unpack('S', "\x00\x01")) === 1)
  6583. {
  6584. $mtime = strrev($mtime);
  6585. }
  6586. $this->MTIME = current(unpack('l', $mtime));
  6587. $this->position += 4;
  6588. // Get the XFL (eXtra FLags)
  6589. $this->XFL = ord($this->compressed_data[$this->position++]);
  6590. // Get the OS (Operating System)
  6591. $this->OS = ord($this->compressed_data[$this->position++]);
  6592. // Parse the FEXTRA
  6593. if ($this->flags & 4)
  6594. {
  6595. // Read subfield IDs
  6596. $this->SI1 = $this->compressed_data[$this->position++];
  6597. $this->SI2 = $this->compressed_data[$this->position++];
  6598. // SI2 set to zero is reserved for future use
  6599. if ($this->SI2 === "\x00")
  6600. {
  6601. return false;
  6602. }
  6603. // Get the length of the extra field
  6604. $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  6605. $this->position += 2;
  6606. // Check the length of the string is still valid
  6607. $this->min_compressed_size += $len + 4;
  6608. if ($this->compressed_size >= $this->min_compressed_size)
  6609. {
  6610. // Set the extra field to the given data
  6611. $this->extra_field = substr($this->compressed_data, $this->position, $len);
  6612. $this->position += $len;
  6613. }
  6614. else
  6615. {
  6616. return false;
  6617. }
  6618. }
  6619. // Parse the FNAME
  6620. if ($this->flags & 8)
  6621. {
  6622. // Get the length of the filename
  6623. $len = strcspn($this->compressed_data, "\x00", $this->position);
  6624. // Check the length of the string is still valid
  6625. $this->min_compressed_size += $len + 1;
  6626. if ($this->compressed_size >= $this->min_compressed_size)
  6627. {
  6628. // Set the original filename to the given string
  6629. $this->filename = substr($this->compressed_data, $this->position, $len);
  6630. $this->position += $len + 1;
  6631. }
  6632. else
  6633. {
  6634. return false;
  6635. }
  6636. }
  6637. // Parse the FCOMMENT
  6638. if ($this->flags & 16)
  6639. {
  6640. // Get the length of the comment
  6641. $len = strcspn($this->compressed_data, "\x00", $this->position);
  6642. // Check the length of the string is still valid
  6643. $this->min_compressed_size += $len + 1;
  6644. if ($this->compressed_size >= $this->min_compressed_size)
  6645. {
  6646. // Set the original comment to the given string
  6647. $this->comment = substr($this->compressed_data, $this->position, $len);
  6648. $this->position += $len + 1;
  6649. }
  6650. else
  6651. {
  6652. return false;
  6653. }
  6654. }
  6655. // Parse the FHCRC
  6656. if ($this->flags & 2)
  6657. {
  6658. // Check the length of the string is still valid
  6659. $this->min_compressed_size += $len + 2;
  6660. if ($this->compressed_size >= $this->min_compressed_size)
  6661. {
  6662. // Read the CRC
  6663. $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  6664. // Check the CRC matches
  6665. if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
  6666. {
  6667. $this->position += 2;
  6668. }
  6669. else
  6670. {
  6671. return false;
  6672. }
  6673. }
  6674. else
  6675. {
  6676. return false;
  6677. }
  6678. }
  6679. // Decompress the actual data
  6680. if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
  6681. {
  6682. return false;
  6683. }
  6684. else
  6685. {
  6686. $this->position = $this->compressed_size - 8;
  6687. }
  6688. // Check CRC of data
  6689. $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  6690. $this->position += 4;
  6691. /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
  6692. {
  6693. return false;
  6694. }*/
  6695. // Check ISIZE of data
  6696. $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  6697. $this->position += 4;
  6698. if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
  6699. {
  6700. return false;
  6701. }
  6702. // Wow, against all odds, we've actually got a valid gzip string
  6703. return true;
  6704. }
  6705. else
  6706. {
  6707. return false;
  6708. }
  6709. }
  6710. }
  6711. /**
  6712. * HTTP Response Parser
  6713. *
  6714. * @package SimplePie
  6715. * @subpackage HTTP
  6716. */
  6717. class SimplePie_HTTP_Parser
  6718. {
  6719. /**
  6720. * HTTP Version
  6721. *
  6722. * @var float
  6723. */
  6724. public $http_version = 0.0;
  6725. /**
  6726. * Status code
  6727. *
  6728. * @var int
  6729. */
  6730. public $status_code = 0;
  6731. /**
  6732. * Reason phrase
  6733. *
  6734. * @var string
  6735. */
  6736. public $reason = '';
  6737. /**
  6738. * Key/value pairs of the headers
  6739. *
  6740. * @var array
  6741. */
  6742. public $headers = array();
  6743. /**
  6744. * Body of the response
  6745. *
  6746. * @var string
  6747. */
  6748. public $body = '';
  6749. /**
  6750. * Current state of the state machine
  6751. *
  6752. * @var string
  6753. */
  6754. protected $state = 'http_version';
  6755. /**
  6756. * Input data
  6757. *
  6758. * @var string
  6759. */
  6760. protected $data = '';
  6761. /**
  6762. * Input data length (to avoid calling strlen() everytime this is needed)
  6763. *
  6764. * @var int
  6765. */
  6766. protected $data_length = 0;
  6767. /**
  6768. * Current position of the pointer
  6769. *
  6770. * @var int
  6771. */
  6772. protected $position = 0;
  6773. /**
  6774. * Name of the hedaer currently being parsed
  6775. *
  6776. * @var string
  6777. */
  6778. protected $name = '';
  6779. /**
  6780. * Value of the hedaer currently being parsed
  6781. *
  6782. * @var string
  6783. */
  6784. protected $value = '';
  6785. /**
  6786. * Create an instance of the class with the input data
  6787. *
  6788. * @param string $data Input data
  6789. */
  6790. public function __construct($data)
  6791. {
  6792. $this->data = $data;
  6793. $this->data_length = strlen($this->data);
  6794. }
  6795. /**
  6796. * Parse the input data
  6797. *
  6798. * @return bool true on success, false on failure
  6799. */
  6800. public function parse()
  6801. {
  6802. while ($this->state && $this->state !== 'emit' && $this->has_data())
  6803. {
  6804. $state = $this->state;
  6805. $this->$state();
  6806. }
  6807. $this->data = '';
  6808. if ($this->state === 'emit' || $this->state === 'body')
  6809. {
  6810. return true;
  6811. }
  6812. else
  6813. {
  6814. $this->http_version = '';
  6815. $this->status_code = '';
  6816. $this->reason = '';
  6817. $this->headers = array();
  6818. $this->body = '';
  6819. return false;
  6820. }
  6821. }
  6822. /**
  6823. * Check whether there is data beyond the pointer
  6824. *
  6825. * @return bool true if there is further data, false if not
  6826. */
  6827. protected function has_data()
  6828. {
  6829. return (bool) ($this->position < $this->data_length);
  6830. }
  6831. /**
  6832. * See if the next character is LWS
  6833. *
  6834. * @return bool true if the next character is LWS, false if not
  6835. */
  6836. protected function is_linear_whitespace()
  6837. {
  6838. return (bool) ($this->data[$this->position] === "\x09"
  6839. || $this->data[$this->position] === "\x20"
  6840. || ($this->data[$this->position] === "\x0A"
  6841. && isset($this->data[$this->position + 1])
  6842. && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
  6843. }
  6844. /**
  6845. * Parse the HTTP version
  6846. */
  6847. protected function http_version()
  6848. {
  6849. if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
  6850. {
  6851. $len = strspn($this->data, '0123456789.', 5);
  6852. $this->http_version = substr($this->data, 5, $len);
  6853. $this->position += 5 + $len;
  6854. if (substr_count($this->http_version, '.') <= 1)
  6855. {
  6856. $this->http_version = (float) $this->http_version;
  6857. $this->position += strspn($this->data, "\x09\x20", $this->position);
  6858. $this->state = 'status';
  6859. }
  6860. else
  6861. {
  6862. $this->state = false;
  6863. }
  6864. }
  6865. else
  6866. {
  6867. $this->state = false;
  6868. }
  6869. }
  6870. /**
  6871. * Parse the status code
  6872. */
  6873. protected function status()
  6874. {
  6875. if ($len = strspn($this->data, '0123456789', $this->position))
  6876. {
  6877. $this->status_code = (int) substr($this->data, $this->position, $len);
  6878. $this->position += $len;
  6879. $this->state = 'reason';
  6880. }
  6881. else
  6882. {
  6883. $this->state = false;
  6884. }
  6885. }
  6886. /**
  6887. * Parse the reason phrase
  6888. */
  6889. protected function reason()
  6890. {
  6891. $len = strcspn($this->data, "\x0A", $this->position);
  6892. $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
  6893. $this->position += $len + 1;
  6894. $this->state = 'new_line';
  6895. }
  6896. /**
  6897. * Deal with a new line, shifting data around as needed
  6898. */
  6899. protected function new_line()
  6900. {
  6901. $this->value = trim($this->value, "\x0D\x20");
  6902. if ($this->name !== '' && $this->value !== '')
  6903. {
  6904. $this->name = strtolower($this->name);
  6905. // We should only use the last Content-Type header. c.f. issue #1
  6906. if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
  6907. {
  6908. $this->headers[$this->name] .= ', ' . $this->value;
  6909. }
  6910. else
  6911. {
  6912. $this->headers[$this->name] = $this->value;
  6913. }
  6914. }
  6915. $this->name = '';
  6916. $this->value = '';
  6917. if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
  6918. {
  6919. $this->position += 2;
  6920. $this->state = 'body';
  6921. }
  6922. elseif ($this->data[$this->position] === "\x0A")
  6923. {
  6924. $this->position++;
  6925. $this->state = 'body';
  6926. }
  6927. else
  6928. {
  6929. $this->state = 'name';
  6930. }
  6931. }
  6932. /**
  6933. * Parse a header name
  6934. */
  6935. protected function name()
  6936. {
  6937. $len = strcspn($this->data, "\x0A:", $this->position);
  6938. if (isset($this->data[$this->position + $len]))
  6939. {
  6940. if ($this->data[$this->position + $len] === "\x0A")
  6941. {
  6942. $this->position += $len;
  6943. $this->state = 'new_line';
  6944. }
  6945. else
  6946. {
  6947. $this->name = substr($this->data, $this->position, $len);
  6948. $this->position += $len + 1;
  6949. $this->state = 'value';
  6950. }
  6951. }
  6952. else
  6953. {
  6954. $this->state = false;
  6955. }
  6956. }
  6957. /**
  6958. * Parse LWS, replacing consecutive LWS characters with a single space
  6959. */
  6960. protected function linear_whitespace()
  6961. {
  6962. do
  6963. {
  6964. if (substr($this->data, $this->position, 2) === "\x0D\x0A")
  6965. {
  6966. $this->position += 2;
  6967. }
  6968. elseif ($this->data[$this->position] === "\x0A")
  6969. {
  6970. $this->position++;
  6971. }
  6972. $this->position += strspn($this->data, "\x09\x20", $this->position);
  6973. } while ($this->has_data() && $this->is_linear_whitespace());
  6974. $this->value .= "\x20";
  6975. }
  6976. /**
  6977. * See what state to move to while within non-quoted header values
  6978. */
  6979. protected function value()
  6980. {
  6981. if ($this->is_linear_whitespace())
  6982. {
  6983. $this->linear_whitespace();
  6984. }
  6985. else
  6986. {
  6987. switch ($this->data[$this->position])
  6988. {
  6989. case '"':
  6990. // Workaround for ETags: we have to include the quotes as
  6991. // part of the tag.
  6992. if (strtolower($this->name) === 'etag')
  6993. {
  6994. $this->value .= '"';
  6995. $this->position++;
  6996. $this->state = 'value_char';
  6997. break;
  6998. }
  6999. $this->position++;
  7000. $this->state = 'quote';
  7001. break;
  7002. case "\x0A":
  7003. $this->position++;
  7004. $this->state = 'new_line';
  7005. break;
  7006. default:
  7007. $this->state = 'value_char';
  7008. break;
  7009. }
  7010. }
  7011. }
  7012. /**
  7013. * Parse a header value while outside quotes
  7014. */
  7015. protected function value_char()
  7016. {
  7017. $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
  7018. $this->value .= substr($this->data, $this->position, $len);
  7019. $this->position += $len;
  7020. $this->state = 'value';
  7021. }
  7022. /**
  7023. * See what state to move to while within quoted header values
  7024. */
  7025. protected function quote()
  7026. {
  7027. if ($this->is_linear_whitespace())
  7028. {
  7029. $this->linear_whitespace();
  7030. }
  7031. else
  7032. {
  7033. switch ($this->data[$this->position])
  7034. {
  7035. case '"':
  7036. $this->position++;
  7037. $this->state = 'value';
  7038. break;
  7039. case "\x0A":
  7040. $this->position++;
  7041. $this->state = 'new_line';
  7042. break;
  7043. case '\\':
  7044. $this->position++;
  7045. $this->state = 'quote_escaped';
  7046. break;
  7047. default:
  7048. $this->state = 'quote_char';
  7049. break;
  7050. }
  7051. }
  7052. }
  7053. /**
  7054. * Parse a header value while within quotes
  7055. */
  7056. protected function quote_char()
  7057. {
  7058. $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
  7059. $this->value .= substr($this->data, $this->position, $len);
  7060. $this->position += $len;
  7061. $this->state = 'value';
  7062. }
  7063. /**
  7064. * Parse an escaped character within quotes
  7065. */
  7066. protected function quote_escaped()
  7067. {
  7068. $this->value .= $this->data[$this->position];
  7069. $this->position++;
  7070. $this->state = 'quote';
  7071. }
  7072. /**
  7073. * Parse the body
  7074. */
  7075. protected function body()
  7076. {
  7077. $this->body = substr($this->data, $this->position);
  7078. if (!empty($this->headers['transfer-encoding']))
  7079. {
  7080. unset($this->headers['transfer-encoding']);
  7081. $this->state = 'chunked';
  7082. }
  7083. else
  7084. {
  7085. $this->state = 'emit';
  7086. }
  7087. }
  7088. /**
  7089. * Parsed a "Transfer-Encoding: chunked" body
  7090. */
  7091. protected function chunked()
  7092. {
  7093. if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
  7094. {
  7095. $this->state = 'emit';
  7096. return;
  7097. }
  7098. $decoded = '';
  7099. $encoded = $this->body;
  7100. while (true)
  7101. {
  7102. $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
  7103. if (!$is_chunked)
  7104. {
  7105. // Looks like it's not chunked after all
  7106. $this->state = 'emit';
  7107. return;
  7108. }
  7109. $length = hexdec(trim($matches[1]));
  7110. if ($length === 0)
  7111. {
  7112. // Ignore trailer headers
  7113. $this->state = 'emit';
  7114. $this->body = $decoded;
  7115. return;
  7116. }
  7117. $chunk_length = strlen($matches[0]);
  7118. $decoded .= $part = substr($encoded, $chunk_length, $length);
  7119. $encoded = substr($encoded, $chunk_length + $length + 2);
  7120. if (trim($encoded) === '0' || empty($encoded))
  7121. {
  7122. $this->state = 'emit';
  7123. $this->body = $decoded;
  7124. return;
  7125. }
  7126. }
  7127. }
  7128. }
  7129. /**
  7130. * IRI parser/serialiser/normaliser
  7131. *
  7132. * @package SimplePie
  7133. * @subpackage HTTP
  7134. * @author Geoffrey Sneddon
  7135. * @author Steve Minutillo
  7136. * @author Ryan McCue
  7137. * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
  7138. * @license http://www.opensource.org/licenses/bsd-license.php
  7139. */
  7140. class SimplePie_IRI
  7141. {
  7142. /**
  7143. * Scheme
  7144. *
  7145. * @var string
  7146. */
  7147. protected $scheme = null;
  7148. /**
  7149. * User Information
  7150. *
  7151. * @var string
  7152. */
  7153. protected $iuserinfo = null;
  7154. /**
  7155. * ihost
  7156. *
  7157. * @var string
  7158. */
  7159. protected $ihost = null;
  7160. /**
  7161. * Port
  7162. *
  7163. * @var string
  7164. */
  7165. protected $port = null;
  7166. /**
  7167. * ipath
  7168. *
  7169. * @var string
  7170. */
  7171. protected $ipath = '';
  7172. /**
  7173. * iquery
  7174. *
  7175. * @var string
  7176. */
  7177. protected $iquery = null;
  7178. /**
  7179. * ifragment
  7180. *
  7181. * @var string
  7182. */
  7183. protected $ifragment = null;
  7184. /**
  7185. * Normalization database
  7186. *
  7187. * Each key is the scheme, each value is an array with each key as the IRI
  7188. * part and value as the default value for that part.
  7189. */
  7190. protected $normalization = array(
  7191. 'acap' => array(
  7192. 'port' => 674
  7193. ),
  7194. 'dict' => array(
  7195. 'port' => 2628
  7196. ),
  7197. 'file' => array(
  7198. 'ihost' => 'localhost'
  7199. ),
  7200. 'http' => array(
  7201. 'port' => 80,
  7202. 'ipath' => '/'
  7203. ),
  7204. 'https' => array(
  7205. 'port' => 443,
  7206. 'ipath' => '/'
  7207. ),
  7208. );
  7209. /**
  7210. * Return the entire IRI when you try and read the object as a string
  7211. *
  7212. * @return string
  7213. */
  7214. public function __toString()
  7215. {
  7216. return $this->get_iri();
  7217. }
  7218. /**
  7219. * Overload __set() to provide access via properties
  7220. *
  7221. * @param string $name Property name
  7222. * @param mixed $value Property value
  7223. */
  7224. public function __set($name, $value)
  7225. {
  7226. if (method_exists($this, 'set_' . $name))
  7227. {
  7228. call_user_func(array($this, 'set_' . $name), $value);
  7229. }
  7230. elseif (
  7231. $name === 'iauthority'
  7232. || $name === 'iuserinfo'
  7233. || $name === 'ihost'
  7234. || $name === 'ipath'
  7235. || $name === 'iquery'
  7236. || $name === 'ifragment'
  7237. )
  7238. {
  7239. call_user_func(array($this, 'set_' . substr($name, 1)), $value);
  7240. }
  7241. }
  7242. /**
  7243. * Overload __get() to provide access via properties
  7244. *
  7245. * @param string $name Property name
  7246. * @return mixed
  7247. */
  7248. public function __get($name)
  7249. {
  7250. // isset() returns false for null, we don't want to do that
  7251. // Also why we use array_key_exists below instead of isset()
  7252. $props = get_object_vars($this);
  7253. if (
  7254. $name === 'iri' ||
  7255. $name === 'uri' ||
  7256. $name === 'iauthority' ||
  7257. $name === 'authority'
  7258. )
  7259. {
  7260. $return = $this->{"get_$name"}();
  7261. }
  7262. elseif (array_key_exists($name, $props))
  7263. {
  7264. $return = $this->$name;
  7265. }
  7266. // host -> ihost
  7267. elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
  7268. {
  7269. $name = $prop;
  7270. $return = $this->$prop;
  7271. }
  7272. // ischeme -> scheme
  7273. elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
  7274. {
  7275. $name = $prop;
  7276. $return = $this->$prop;
  7277. }
  7278. else
  7279. {
  7280. trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
  7281. $return = null;
  7282. }
  7283. if ($return === null && isset($this->normalization[$this->scheme][$name]))
  7284. {
  7285. return $this->normalization[$this->scheme][$name];
  7286. }
  7287. else
  7288. {
  7289. return $return;
  7290. }
  7291. }
  7292. /**
  7293. * Overload __isset() to provide access via properties
  7294. *
  7295. * @param string $name Property name
  7296. * @return bool
  7297. */
  7298. public function __isset($name)
  7299. {
  7300. if (method_exists($this, 'get_' . $name) || isset($this->$name))
  7301. {
  7302. return true;
  7303. }
  7304. else
  7305. {
  7306. return false;
  7307. }
  7308. }
  7309. /**
  7310. * Overload __unset() to provide access via properties
  7311. *
  7312. * @param string $name Property name
  7313. */
  7314. public function __unset($name)
  7315. {
  7316. if (method_exists($this, 'set_' . $name))
  7317. {
  7318. call_user_func(array($this, 'set_' . $name), '');
  7319. }
  7320. }
  7321. /**
  7322. * Create a new IRI object, from a specified string
  7323. *
  7324. * @param string $iri
  7325. */
  7326. public function __construct($iri = null)
  7327. {
  7328. $this->set_iri($iri);
  7329. }
  7330. /**
  7331. * Create a new IRI object by resolving a relative IRI
  7332. *
  7333. * Returns false if $base is not absolute, otherwise an IRI.
  7334. *
  7335. * @param IRI|string $base (Absolute) Base IRI
  7336. * @param IRI|string $relative Relative IRI
  7337. * @return IRI|false
  7338. */
  7339. public static function absolutize($base, $relative)
  7340. {
  7341. if (!($relative instanceof SimplePie_IRI))
  7342. {
  7343. $relative = new SimplePie_IRI($relative);
  7344. }
  7345. if (!$relative->is_valid())
  7346. {
  7347. return false;
  7348. }
  7349. elseif ($relative->scheme !== null)
  7350. {
  7351. return clone $relative;
  7352. }
  7353. else
  7354. {
  7355. if (!($base instanceof SimplePie_IRI))
  7356. {
  7357. $base = new SimplePie_IRI($base);
  7358. }
  7359. if ($base->scheme !== null && $base->is_valid())
  7360. {
  7361. if ($relative->get_iri() !== '')
  7362. {
  7363. if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
  7364. {
  7365. $target = clone $relative;
  7366. $target->scheme = $base->scheme;
  7367. }
  7368. else
  7369. {
  7370. $target = new SimplePie_IRI;
  7371. $target->scheme = $base->scheme;
  7372. $target->iuserinfo = $base->iuserinfo;
  7373. $target->ihost = $base->ihost;
  7374. $target->port = $base->port;
  7375. if ($relative->ipath !== '')
  7376. {
  7377. if ($relative->ipath[0] === '/')
  7378. {
  7379. $target->ipath = $relative->ipath;
  7380. }
  7381. elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
  7382. {
  7383. $target->ipath = '/' . $relative->ipath;
  7384. }
  7385. elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
  7386. {
  7387. $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
  7388. }
  7389. else
  7390. {
  7391. $target->ipath = $relative->ipath;
  7392. }
  7393. $target->ipath = $target->remove_dot_segments($target->ipath);
  7394. $target->iquery = $relative->iquery;
  7395. }
  7396. else
  7397. {
  7398. $target->ipath = $base->ipath;
  7399. if ($relative->iquery !== null)
  7400. {
  7401. $target->iquery = $relative->iquery;
  7402. }
  7403. elseif ($base->iquery !== null)
  7404. {
  7405. $target->iquery = $base->iquery;
  7406. }
  7407. }
  7408. $target->ifragment = $relative->ifragment;
  7409. }
  7410. }
  7411. else
  7412. {
  7413. $target = clone $base;
  7414. $target->ifragment = null;
  7415. }
  7416. $target->scheme_normalization();
  7417. return $target;
  7418. }
  7419. else
  7420. {
  7421. return false;
  7422. }
  7423. }
  7424. }
  7425. /**
  7426. * Parse an IRI into scheme/authority/path/query/fragment segments
  7427. *
  7428. * @param string $iri
  7429. * @return array
  7430. */
  7431. protected function parse_iri($iri)
  7432. {
  7433. $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
  7434. if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
  7435. {
  7436. if ($match[1] === '')
  7437. {
  7438. $match['scheme'] = null;
  7439. }
  7440. if (!isset($match[3]) || $match[3] === '')
  7441. {
  7442. $match['authority'] = null;
  7443. }
  7444. if (!isset($match[5]))
  7445. {
  7446. $match['path'] = '';
  7447. }
  7448. if (!isset($match[6]) || $match[6] === '')
  7449. {
  7450. $match['query'] = null;
  7451. }
  7452. if (!isset($match[8]) || $match[8] === '')
  7453. {
  7454. $match['fragment'] = null;
  7455. }
  7456. return $match;
  7457. }
  7458. else
  7459. {
  7460. trigger_error('This should never happen', E_USER_ERROR);
  7461. die;
  7462. }
  7463. }
  7464. /**
  7465. * Remove dot segments from a path
  7466. *
  7467. * @param string $input
  7468. * @return string
  7469. */
  7470. protected function remove_dot_segments($input)
  7471. {
  7472. $output = '';
  7473. while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
  7474. {
  7475. // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
  7476. if (strpos($input, '../') === 0)
  7477. {
  7478. $input = substr($input, 3);
  7479. }
  7480. elseif (strpos($input, './') === 0)
  7481. {
  7482. $input = substr($input, 2);
  7483. }
  7484. // 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,
  7485. elseif (strpos($input, '/./') === 0)
  7486. {
  7487. $input = substr($input, 2);
  7488. }
  7489. elseif ($input === '/.')
  7490. {
  7491. $input = '/';
  7492. }
  7493. // 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,
  7494. elseif (strpos($input, '/../') === 0)
  7495. {
  7496. $input = substr($input, 3);
  7497. $output = substr_replace($output, '', strrpos($output, '/'));
  7498. }
  7499. elseif ($input === '/..')
  7500. {
  7501. $input = '/';
  7502. $output = substr_replace($output, '', strrpos($output, '/'));
  7503. }
  7504. // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
  7505. elseif ($input === '.' || $input === '..')
  7506. {
  7507. $input = '';
  7508. }
  7509. // 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
  7510. elseif (($pos = strpos($input, '/', 1)) !== false)
  7511. {
  7512. $output .= substr($input, 0, $pos);
  7513. $input = substr_replace($input, '', 0, $pos);
  7514. }
  7515. else
  7516. {
  7517. $output .= $input;
  7518. $input = '';
  7519. }
  7520. }
  7521. return $output . $input;
  7522. }
  7523. /**
  7524. * Replace invalid character with percent encoding
  7525. *
  7526. * @param string $string Input string
  7527. * @param string $extra_chars Valid characters not in iunreserved or
  7528. * iprivate (this is ASCII-only)
  7529. * @param bool $iprivate Allow iprivate
  7530. * @return string
  7531. */
  7532. protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
  7533. {
  7534. // Normalize as many pct-encoded sections as possible
  7535. $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
  7536. // Replace invalid percent characters
  7537. $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
  7538. // Add unreserved and % to $extra_chars (the latter is safe because all
  7539. // pct-encoded sections are now valid).
  7540. $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
  7541. // Now replace any bytes that aren't allowed with their pct-encoded versions
  7542. $position = 0;
  7543. $strlen = strlen($string);
  7544. while (($position += strspn($string, $extra_chars, $position)) < $strlen)
  7545. {
  7546. $value = ord($string[$position]);
  7547. // Start position
  7548. $start = $position;
  7549. // By default we are valid
  7550. $valid = true;
  7551. // No one byte sequences are valid due to the while.
  7552. // Two byte sequence:
  7553. if (($value & 0xE0) === 0xC0)
  7554. {
  7555. $character = ($value & 0x1F) << 6;
  7556. $length = 2;
  7557. $remaining = 1;
  7558. }
  7559. // Three byte sequence:
  7560. elseif (($value & 0xF0) === 0xE0)
  7561. {
  7562. $character = ($value & 0x0F) << 12;
  7563. $length = 3;
  7564. $remaining = 2;
  7565. }
  7566. // Four byte sequence:
  7567. elseif (($value & 0xF8) === 0xF0)
  7568. {
  7569. $character = ($value & 0x07) << 18;
  7570. $length = 4;
  7571. $remaining = 3;
  7572. }
  7573. // Invalid byte:
  7574. else
  7575. {
  7576. $valid = false;
  7577. $length = 1;
  7578. $remaining = 0;
  7579. }
  7580. if ($remaining)
  7581. {
  7582. if ($position + $length <= $strlen)
  7583. {
  7584. for ($position++; $remaining; $position++)
  7585. {
  7586. $value = ord($string[$position]);
  7587. // Check that the byte is valid, then add it to the character:
  7588. if (($value & 0xC0) === 0x80)
  7589. {
  7590. $character |= ($value & 0x3F) << (--$remaining * 6);
  7591. }
  7592. // If it is invalid, count the sequence as invalid and reprocess the current byte:
  7593. else
  7594. {
  7595. $valid = false;
  7596. $position--;
  7597. break;
  7598. }
  7599. }
  7600. }
  7601. else
  7602. {
  7603. $position = $strlen - 1;
  7604. $valid = false;
  7605. }
  7606. }
  7607. // Percent encode anything invalid or not in ucschar
  7608. if (
  7609. // Invalid sequences
  7610. !$valid
  7611. // Non-shortest form sequences are invalid
  7612. || $length > 1 && $character <= 0x7F
  7613. || $length > 2 && $character <= 0x7FF
  7614. || $length > 3 && $character <= 0xFFFF
  7615. // Outside of range of ucschar codepoints
  7616. // Noncharacters
  7617. || ($character & 0xFFFE) === 0xFFFE
  7618. || $character >= 0xFDD0 && $character <= 0xFDEF
  7619. || (
  7620. // Everything else not in ucschar
  7621. $character > 0xD7FF && $character < 0xF900
  7622. || $character < 0xA0
  7623. || $character > 0xEFFFD
  7624. )
  7625. && (
  7626. // Everything not in iprivate, if it applies
  7627. !$iprivate
  7628. || $character < 0xE000
  7629. || $character > 0x10FFFD
  7630. )
  7631. )
  7632. {
  7633. // If we were a character, pretend we weren't, but rather an error.
  7634. if ($valid)
  7635. $position--;
  7636. for ($j = $start; $j <= $position; $j++)
  7637. {
  7638. $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
  7639. $j += 2;
  7640. $position += 2;
  7641. $strlen += 2;
  7642. }
  7643. }
  7644. }
  7645. return $string;
  7646. }
  7647. /**
  7648. * Callback function for preg_replace_callback.
  7649. *
  7650. * Removes sequences of percent encoded bytes that represent UTF-8
  7651. * encoded characters in iunreserved
  7652. *
  7653. * @param array $match PCRE match
  7654. * @return string Replacement
  7655. */
  7656. protected function remove_iunreserved_percent_encoded($match)
  7657. {
  7658. // As we just have valid percent encoded sequences we can just explode
  7659. // and ignore the first member of the returned array (an empty string).
  7660. $bytes = explode('%', $match[0]);
  7661. // Initialize the new string (this is what will be returned) and that
  7662. // there are no bytes remaining in the current sequence (unsurprising
  7663. // at the first byte!).
  7664. $string = '';
  7665. $remaining = 0;
  7666. // Loop over each and every byte, and set $value to its value
  7667. for ($i = 1, $len = count($bytes); $i < $len; $i++)
  7668. {
  7669. $value = hexdec($bytes[$i]);
  7670. // If we're the first byte of sequence:
  7671. if (!$remaining)
  7672. {
  7673. // Start position
  7674. $start = $i;
  7675. // By default we are valid
  7676. $valid = true;
  7677. // One byte sequence:
  7678. if ($value <= 0x7F)
  7679. {
  7680. $character = $value;
  7681. $length = 1;
  7682. }
  7683. // Two byte sequence:
  7684. elseif (($value & 0xE0) === 0xC0)
  7685. {
  7686. $character = ($value & 0x1F) << 6;
  7687. $length = 2;
  7688. $remaining = 1;
  7689. }
  7690. // Three byte sequence:
  7691. elseif (($value & 0xF0) === 0xE0)
  7692. {
  7693. $character = ($value & 0x0F) << 12;
  7694. $length = 3;
  7695. $remaining = 2;
  7696. }
  7697. // Four byte sequence:
  7698. elseif (($value & 0xF8) === 0xF0)
  7699. {
  7700. $character = ($value & 0x07) << 18;
  7701. $length = 4;
  7702. $remaining = 3;
  7703. }
  7704. // Invalid byte:
  7705. else
  7706. {
  7707. $valid = false;
  7708. $remaining = 0;
  7709. }
  7710. }
  7711. // Continuation byte:
  7712. else
  7713. {
  7714. // Check that the byte is valid, then add it to the character:
  7715. if (($value & 0xC0) === 0x80)
  7716. {
  7717. $remaining--;
  7718. $character |= ($value & 0x3F) << ($remaining * 6);
  7719. }
  7720. // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
  7721. else
  7722. {
  7723. $valid = false;
  7724. $remaining = 0;
  7725. $i--;
  7726. }
  7727. }
  7728. // If we've reached the end of the current byte sequence, append it to Unicode::$data
  7729. if (!$remaining)
  7730. {
  7731. // Percent encode anything invalid or not in iunreserved
  7732. if (
  7733. // Invalid sequences
  7734. !$valid
  7735. // Non-shortest form sequences are invalid
  7736. || $length > 1 && $character <= 0x7F
  7737. || $length > 2 && $character <= 0x7FF
  7738. || $length > 3 && $character <= 0xFFFF
  7739. // Outside of range of iunreserved codepoints
  7740. || $character < 0x2D
  7741. || $character > 0xEFFFD
  7742. // Noncharacters
  7743. || ($character & 0xFFFE) === 0xFFFE
  7744. || $character >= 0xFDD0 && $character <= 0xFDEF
  7745. // Everything else not in iunreserved (this is all BMP)
  7746. || $character === 0x2F
  7747. || $character > 0x39 && $character < 0x41
  7748. || $character > 0x5A && $character < 0x61
  7749. || $character > 0x7A && $character < 0x7E
  7750. || $character > 0x7E && $character < 0xA0
  7751. || $character > 0xD7FF && $character < 0xF900
  7752. )
  7753. {
  7754. for ($j = $start; $j <= $i; $j++)
  7755. {
  7756. $string .= '%' . strtoupper($bytes[$j]);
  7757. }
  7758. }
  7759. else
  7760. {
  7761. for ($j = $start; $j <= $i; $j++)
  7762. {
  7763. $string .= chr(hexdec($bytes[$j]));
  7764. }
  7765. }
  7766. }
  7767. }
  7768. // If we have any bytes left over they are invalid (i.e., we are
  7769. // mid-way through a multi-byte sequence)
  7770. if ($remaining)
  7771. {
  7772. for ($j = $start; $j < $len; $j++)
  7773. {
  7774. $string .= '%' . strtoupper($bytes[$j]);
  7775. }
  7776. }
  7777. return $string;
  7778. }
  7779. protected function scheme_normalization()
  7780. {
  7781. if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
  7782. {
  7783. $this->iuserinfo = null;
  7784. }
  7785. if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
  7786. {
  7787. $this->ihost = null;
  7788. }
  7789. if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
  7790. {
  7791. $this->port = null;
  7792. }
  7793. if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
  7794. {
  7795. $this->ipath = '';
  7796. }
  7797. if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
  7798. {
  7799. $this->iquery = null;
  7800. }
  7801. if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
  7802. {
  7803. $this->ifragment = null;
  7804. }
  7805. }
  7806. /**
  7807. * Check if the object represents a valid IRI. This needs to be done on each
  7808. * call as some things change depending on another part of the IRI.
  7809. *
  7810. * @return bool
  7811. */
  7812. public function is_valid()
  7813. {
  7814. $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
  7815. if ($this->ipath !== '' &&
  7816. (
  7817. $isauthority && (
  7818. $this->ipath[0] !== '/' ||
  7819. substr($this->ipath, 0, 2) === '//'
  7820. ) ||
  7821. (
  7822. $this->scheme === null &&
  7823. !$isauthority &&
  7824. strpos($this->ipath, ':') !== false &&
  7825. (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
  7826. )
  7827. )
  7828. )
  7829. {
  7830. return false;
  7831. }
  7832. return true;
  7833. }
  7834. /**
  7835. * Set the entire IRI. Returns true on success, false on failure (if there
  7836. * are any invalid characters).
  7837. *
  7838. * @param string $iri
  7839. * @return bool
  7840. */
  7841. public function set_iri($iri)
  7842. {
  7843. static $cache;
  7844. if (!$cache)
  7845. {
  7846. $cache = array();
  7847. }
  7848. if ($iri === null)
  7849. {
  7850. return true;
  7851. }
  7852. elseif (isset($cache[$iri]))
  7853. {
  7854. list($this->scheme,
  7855. $this->iuserinfo,
  7856. $this->ihost,
  7857. $this->port,
  7858. $this->ipath,
  7859. $this->iquery,
  7860. $this->ifragment,
  7861. $return) = $cache[$iri];
  7862. return $return;
  7863. }
  7864. else
  7865. {
  7866. $parsed = $this->parse_iri((string) $iri);
  7867. $return = $this->set_scheme($parsed['scheme'])
  7868. && $this->set_authority($parsed['authority'])
  7869. && $this->set_path($parsed['path'])
  7870. && $this->set_query($parsed['query'])
  7871. && $this->set_fragment($parsed['fragment']);
  7872. $cache[$iri] = array($this->scheme,
  7873. $this->iuserinfo,
  7874. $this->ihost,
  7875. $this->port,
  7876. $this->ipath,
  7877. $this->iquery,
  7878. $this->ifragment,
  7879. $return);
  7880. return $return;
  7881. }
  7882. }
  7883. /**
  7884. * Set the scheme. Returns true on success, false on failure (if there are
  7885. * any invalid characters).
  7886. *
  7887. * @param string $scheme
  7888. * @return bool
  7889. */
  7890. public function set_scheme($scheme)
  7891. {
  7892. if ($scheme === null)
  7893. {
  7894. $this->scheme = null;
  7895. }
  7896. elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
  7897. {
  7898. $this->scheme = null;
  7899. return false;
  7900. }
  7901. else
  7902. {
  7903. $this->scheme = strtolower($scheme);
  7904. }
  7905. return true;
  7906. }
  7907. /**
  7908. * Set the authority. Returns true on success, false on failure (if there are
  7909. * any invalid characters).
  7910. *
  7911. * @param string $authority
  7912. * @return bool
  7913. */
  7914. public function set_authority($authority)
  7915. {
  7916. static $cache;
  7917. if (!$cache)
  7918. $cache = array();
  7919. if ($authority === null)
  7920. {
  7921. $this->iuserinfo = null;
  7922. $this->ihost = null;
  7923. $this->port = null;
  7924. return true;
  7925. }
  7926. elseif (isset($cache[$authority]))
  7927. {
  7928. list($this->iuserinfo,
  7929. $this->ihost,
  7930. $this->port,
  7931. $return) = $cache[$authority];
  7932. return $return;
  7933. }
  7934. else
  7935. {
  7936. $remaining = $authority;
  7937. if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
  7938. {
  7939. $iuserinfo = substr($remaining, 0, $iuserinfo_end);
  7940. $remaining = substr($remaining, $iuserinfo_end + 1);
  7941. }
  7942. else
  7943. {
  7944. $iuserinfo = null;
  7945. }
  7946. if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
  7947. {
  7948. if (($port = substr($remaining, $port_start + 1)) === false)
  7949. {
  7950. $port = null;
  7951. }
  7952. $remaining = substr($remaining, 0, $port_start);
  7953. }
  7954. else
  7955. {
  7956. $port = null;
  7957. }
  7958. $return = $this->set_userinfo($iuserinfo) &&
  7959. $this->set_host($remaining) &&
  7960. $this->set_port($port);
  7961. $cache[$authority] = array($this->iuserinfo,
  7962. $this->ihost,
  7963. $this->port,
  7964. $return);
  7965. return $return;
  7966. }
  7967. }
  7968. /**
  7969. * Set the iuserinfo.
  7970. *
  7971. * @param string $iuserinfo
  7972. * @return bool
  7973. */
  7974. public function set_userinfo($iuserinfo)
  7975. {
  7976. if ($iuserinfo === null)
  7977. {
  7978. $this->iuserinfo = null;
  7979. }
  7980. else
  7981. {
  7982. $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
  7983. $this->scheme_normalization();
  7984. }
  7985. return true;
  7986. }
  7987. /**
  7988. * Set the ihost. Returns true on success, false on failure (if there are
  7989. * any invalid characters).
  7990. *
  7991. * @param string $ihost
  7992. * @return bool
  7993. */
  7994. public function set_host($ihost)
  7995. {
  7996. if ($ihost === null)
  7997. {
  7998. $this->ihost = null;
  7999. return true;
  8000. }
  8001. elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
  8002. {
  8003. if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
  8004. {
  8005. $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
  8006. }
  8007. else
  8008. {
  8009. $this->ihost = null;
  8010. return false;
  8011. }
  8012. }
  8013. else
  8014. {
  8015. $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
  8016. // Lowercase, but ignore pct-encoded sections (as they should
  8017. // remain uppercase). This must be done after the previous step
  8018. // as that can add unescaped characters.
  8019. $position = 0;
  8020. $strlen = strlen($ihost);
  8021. while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
  8022. {
  8023. if ($ihost[$position] === '%')
  8024. {
  8025. $position += 3;
  8026. }
  8027. else
  8028. {
  8029. $ihost[$position] = strtolower($ihost[$position]);
  8030. $position++;
  8031. }
  8032. }
  8033. $this->ihost = $ihost;
  8034. }
  8035. $this->scheme_normalization();
  8036. return true;
  8037. }
  8038. /**
  8039. * Set the port. Returns true on success, false on failure (if there are
  8040. * any invalid characters).
  8041. *
  8042. * @param string $port
  8043. * @return bool
  8044. */
  8045. public function set_port($port)
  8046. {
  8047. if ($port === null)
  8048. {
  8049. $this->port = null;
  8050. return true;
  8051. }
  8052. elseif (strspn($port, '0123456789') === strlen($port))
  8053. {
  8054. $this->port = (int) $port;
  8055. $this->scheme_normalization();
  8056. return true;
  8057. }
  8058. else
  8059. {
  8060. $this->port = null;
  8061. return false;
  8062. }
  8063. }
  8064. /**
  8065. * Set the ipath.
  8066. *
  8067. * @param string $ipath
  8068. * @return bool
  8069. */
  8070. public function set_path($ipath)
  8071. {
  8072. static $cache;
  8073. if (!$cache)
  8074. {
  8075. $cache = array();
  8076. }
  8077. $ipath = (string) $ipath;
  8078. if (isset($cache[$ipath]))
  8079. {
  8080. $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
  8081. }
  8082. else
  8083. {
  8084. $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
  8085. $removed = $this->remove_dot_segments($valid);
  8086. $cache[$ipath] = array($valid, $removed);
  8087. $this->ipath = ($this->scheme !== null) ? $removed : $valid;
  8088. }
  8089. $this->scheme_normalization();
  8090. return true;
  8091. }
  8092. /**
  8093. * Set the iquery.
  8094. *
  8095. * @param string $iquery
  8096. * @return bool
  8097. */
  8098. public function set_query($iquery)
  8099. {
  8100. if ($iquery === null)
  8101. {
  8102. $this->iquery = null;
  8103. }
  8104. else
  8105. {
  8106. $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
  8107. $this->scheme_normalization();
  8108. }
  8109. return true;
  8110. }
  8111. /**
  8112. * Set the ifragment.
  8113. *
  8114. * @param string $ifragment
  8115. * @return bool
  8116. */
  8117. public function set_fragment($ifragment)
  8118. {
  8119. if ($ifragment === null)
  8120. {
  8121. $this->ifragment = null;
  8122. }
  8123. else
  8124. {
  8125. $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
  8126. $this->scheme_normalization();
  8127. }
  8128. return true;
  8129. }
  8130. /**
  8131. * Convert an IRI to a URI (or parts thereof)
  8132. *
  8133. * @return string
  8134. */
  8135. public function to_uri($string)
  8136. {
  8137. static $non_ascii;
  8138. if (!$non_ascii)
  8139. {
  8140. $non_ascii = implode('', range("\x80", "\xFF"));
  8141. }
  8142. $position = 0;
  8143. $strlen = strlen($string);
  8144. while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
  8145. {
  8146. $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
  8147. $position += 3;
  8148. $strlen += 2;
  8149. }
  8150. return $string;
  8151. }
  8152. /**
  8153. * Get the complete IRI
  8154. *
  8155. * @return string
  8156. */
  8157. public function get_iri()
  8158. {
  8159. if (!$this->is_valid())
  8160. {
  8161. return false;
  8162. }
  8163. $iri = '';
  8164. if ($this->scheme !== null)
  8165. {
  8166. $iri .= $this->scheme . ':';
  8167. }
  8168. if (($iauthority = $this->get_iauthority()) !== null)
  8169. {
  8170. $iri .= '//' . $iauthority;
  8171. }
  8172. if ($this->ipath !== '')
  8173. {
  8174. $iri .= $this->ipath;
  8175. }
  8176. elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
  8177. {
  8178. $iri .= $this->normalization[$this->scheme]['ipath'];
  8179. }
  8180. if ($this->iquery !== null)
  8181. {
  8182. $iri .= '?' . $this->iquery;
  8183. }
  8184. if ($this->ifragment !== null)
  8185. {
  8186. $iri .= '#' . $this->ifragment;
  8187. }
  8188. return $iri;
  8189. }
  8190. /**
  8191. * Get the complete URI
  8192. *
  8193. * @return string
  8194. */
  8195. public function get_uri()
  8196. {
  8197. return $this->to_uri($this->get_iri());
  8198. }
  8199. /**
  8200. * Get the complete iauthority
  8201. *
  8202. * @return string
  8203. */
  8204. protected function get_iauthority()
  8205. {
  8206. if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
  8207. {
  8208. $iauthority = '';
  8209. if ($this->iuserinfo !== null)
  8210. {
  8211. $iauthority .= $this->iuserinfo . '@';
  8212. }
  8213. if ($this->ihost !== null)
  8214. {
  8215. $iauthority .= $this->ihost;
  8216. }
  8217. if ($this->port !== null)
  8218. {
  8219. $iauthority .= ':' . $this->port;
  8220. }
  8221. return $iauthority;
  8222. }
  8223. else
  8224. {
  8225. return null;
  8226. }
  8227. }
  8228. /**
  8229. * Get the complete authority
  8230. *
  8231. * @return string
  8232. */
  8233. protected function get_authority()
  8234. {
  8235. $iauthority = $this->get_iauthority();
  8236. if (is_string($iauthority))
  8237. return $this->to_uri($iauthority);
  8238. else
  8239. return $iauthority;
  8240. }
  8241. }
  8242. /**
  8243. * Manages all item-related data
  8244. *
  8245. * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
  8246. *
  8247. * This class can be overloaded with {@see SimplePie::set_item_class()}
  8248. *
  8249. * @package SimplePie
  8250. * @subpackage API
  8251. */
  8252. class SimplePie_Item
  8253. {
  8254. /**
  8255. * Parent feed
  8256. *
  8257. * @access private
  8258. * @var SimplePie
  8259. */
  8260. var $feed;
  8261. /**
  8262. * Raw data
  8263. *
  8264. * @access private
  8265. * @var array
  8266. */
  8267. var $data = array();
  8268. /**
  8269. * Registry object
  8270. *
  8271. * @see set_registry
  8272. * @var SimplePie_Registry
  8273. */
  8274. protected $registry;
  8275. /**
  8276. * Create a new item object
  8277. *
  8278. * This is usually used by {@see SimplePie::get_items} and
  8279. * {@see SimplePie::get_item}. Avoid creating this manually.
  8280. *
  8281. * @param SimplePie $feed Parent feed
  8282. * @param array $data Raw data
  8283. */
  8284. public function __construct($feed, $data)
  8285. {
  8286. $this->feed = $feed;
  8287. $this->data = $data;
  8288. }
  8289. /**
  8290. * Set the registry handler
  8291. *
  8292. * This is usually used by {@see SimplePie_Registry::create}
  8293. *
  8294. * @since 1.3
  8295. * @param SimplePie_Registry $registry
  8296. */
  8297. public function set_registry(SimplePie_Registry $registry)
  8298. {
  8299. $this->registry = $registry;
  8300. }
  8301. /**
  8302. * Get a string representation of the item
  8303. *
  8304. * @return string
  8305. */
  8306. public function __toString()
  8307. {
  8308. return md5(serialize($this->data));
  8309. }
  8310. /**
  8311. * Remove items that link back to this before destroying this object
  8312. */
  8313. public function __destruct()
  8314. {
  8315. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  8316. {
  8317. unset($this->feed);
  8318. }
  8319. }
  8320. /**
  8321. * Get data for an item-level element
  8322. *
  8323. * This method allows you to get access to ANY element/attribute that is a
  8324. * sub-element of the item/entry tag.
  8325. *
  8326. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  8327. *
  8328. * @since 1.0
  8329. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  8330. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  8331. * @param string $tag Tag name
  8332. * @return array
  8333. */
  8334. public function get_item_tags($namespace, $tag)
  8335. {
  8336. if (isset($this->data['child'][$namespace][$tag]))
  8337. {
  8338. return $this->data['child'][$namespace][$tag];
  8339. }
  8340. else
  8341. {
  8342. return null;
  8343. }
  8344. }
  8345. /**
  8346. * Get the base URL value from the parent feed
  8347. *
  8348. * Uses `<xml:base>`
  8349. *
  8350. * @param array $element
  8351. * @return string
  8352. */
  8353. public function get_base($element = array())
  8354. {
  8355. return $this->feed->get_base($element);
  8356. }
  8357. /**
  8358. * Sanitize feed data
  8359. *
  8360. * @access private
  8361. * @see SimplePie::sanitize()
  8362. * @param string $data Data to sanitize
  8363. * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
  8364. * @param string $base Base URL to resolve URLs against
  8365. * @return string Sanitized data
  8366. */
  8367. public function sanitize($data, $type, $base = '')
  8368. {
  8369. return $this->feed->sanitize($data, $type, $base);
  8370. }
  8371. /**
  8372. * Get the parent feed
  8373. *
  8374. * Note: this may not work as you think for multifeeds!
  8375. *
  8376. * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
  8377. * @since 1.0
  8378. * @return SimplePie
  8379. */
  8380. public function get_feed()
  8381. {
  8382. return $this->feed;
  8383. }
  8384. /**
  8385. * Get the unique identifier for the item
  8386. *
  8387. * This is usually used when writing code to check for new items in a feed.
  8388. *
  8389. * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
  8390. * for RDF. If none of these are supplied (or `$hash` is true), creates an
  8391. * MD5 hash based on the permalink and title. If either of those are not
  8392. * supplied, creates a hash based on the full feed data.
  8393. *
  8394. * @since Beta 2
  8395. * @param boolean $hash Should we force using a hash instead of the supplied ID?
  8396. * @return string
  8397. */
  8398. public function get_id($hash = false)
  8399. {
  8400. if (!$hash)
  8401. {
  8402. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
  8403. {
  8404. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8405. }
  8406. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
  8407. {
  8408. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8409. }
  8410. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  8411. {
  8412. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8413. }
  8414. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
  8415. {
  8416. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8417. }
  8418. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
  8419. {
  8420. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8421. }
  8422. elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
  8423. {
  8424. return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
  8425. }
  8426. elseif (($return = $this->get_permalink()) !== null)
  8427. {
  8428. return $return;
  8429. }
  8430. elseif (($return = $this->get_title()) !== null)
  8431. {
  8432. return $return;
  8433. }
  8434. }
  8435. if ($this->get_permalink() !== null || $this->get_title() !== null)
  8436. {
  8437. return md5($this->get_permalink() . $this->get_title());
  8438. }
  8439. else
  8440. {
  8441. return md5(serialize($this->data));
  8442. }
  8443. }
  8444. /**
  8445. * Get the title of the item
  8446. *
  8447. * Uses `<atom:title>`, `<title>` or `<dc:title>`
  8448. *
  8449. * @since Beta 2 (previously called `get_item_title` since 0.8)
  8450. * @return string|null
  8451. */
  8452. public function get_title()
  8453. {
  8454. if (!isset($this->data['title']))
  8455. {
  8456. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  8457. {
  8458. $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]));
  8459. }
  8460. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  8461. {
  8462. $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]));
  8463. }
  8464. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  8465. {
  8466. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  8467. }
  8468. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  8469. {
  8470. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  8471. }
  8472. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  8473. {
  8474. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  8475. }
  8476. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  8477. {
  8478. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8479. }
  8480. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  8481. {
  8482. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8483. }
  8484. else
  8485. {
  8486. $this->data['title'] = null;
  8487. }
  8488. }
  8489. return $this->data['title'];
  8490. }
  8491. /**
  8492. * Get the content for the item
  8493. *
  8494. * Prefers summaries over full content , but will return full content if a
  8495. * summary does not exist.
  8496. *
  8497. * To prefer full content instead, use {@see get_content}
  8498. *
  8499. * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
  8500. * `<itunes:subtitle>`
  8501. *
  8502. * @since 0.8
  8503. * @param boolean $description_only Should we avoid falling back to the content?
  8504. * @return string|null
  8505. */
  8506. public function get_description($description_only = false)
  8507. {
  8508. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
  8509. {
  8510. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  8511. }
  8512. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
  8513. {
  8514. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  8515. }
  8516. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  8517. {
  8518. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  8519. }
  8520. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  8521. {
  8522. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  8523. }
  8524. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  8525. {
  8526. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8527. }
  8528. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  8529. {
  8530. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8531. }
  8532. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  8533. {
  8534. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  8535. }
  8536. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  8537. {
  8538. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8539. }
  8540. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  8541. {
  8542. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
  8543. }
  8544. elseif (!$description_only)
  8545. {
  8546. return $this->get_content(true);
  8547. }
  8548. else
  8549. {
  8550. return null;
  8551. }
  8552. }
  8553. /**
  8554. * Get the content for the item
  8555. *
  8556. * Prefers full content over summaries, but will return a summary if full
  8557. * content does not exist.
  8558. *
  8559. * To prefer summaries instead, use {@see get_description}
  8560. *
  8561. * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
  8562. *
  8563. * @since 1.0
  8564. * @param boolean $content_only Should we avoid falling back to the description?
  8565. * @return string|null
  8566. */
  8567. public function get_content($content_only = false)
  8568. {
  8569. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
  8570. {
  8571. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  8572. }
  8573. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
  8574. {
  8575. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  8576. }
  8577. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
  8578. {
  8579. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  8580. }
  8581. elseif (!$content_only)
  8582. {
  8583. return $this->get_description(true);
  8584. }
  8585. else
  8586. {
  8587. return null;
  8588. }
  8589. }
  8590. /**
  8591. * Get a category for the item
  8592. *
  8593. * @since Beta 3 (previously called `get_categories()` since Beta 2)
  8594. * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
  8595. * @return SimplePie_Category|null
  8596. */
  8597. public function get_category($key = 0)
  8598. {
  8599. $categories = $this->get_categories();
  8600. if (isset($categories[$key]))
  8601. {
  8602. return $categories[$key];
  8603. }
  8604. else
  8605. {
  8606. return null;
  8607. }
  8608. }
  8609. /**
  8610. * Get all categories for the item
  8611. *
  8612. * Uses `<atom:category>`, `<category>` or `<dc:subject>`
  8613. *
  8614. * @since Beta 3
  8615. * @return array|null List of {@see SimplePie_Category} objects
  8616. */
  8617. public function get_categories()
  8618. {
  8619. $categories = array();
  8620. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  8621. {
  8622. $term = null;
  8623. $scheme = null;
  8624. $label = null;
  8625. if (isset($category['attribs']['']['term']))
  8626. {
  8627. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  8628. }
  8629. if (isset($category['attribs']['']['scheme']))
  8630. {
  8631. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  8632. }
  8633. if (isset($category['attribs']['']['label']))
  8634. {
  8635. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  8636. }
  8637. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  8638. }
  8639. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  8640. {
  8641. // This is really the label, but keep this as the term also for BC.
  8642. // Label will also work on retrieving because that falls back to term.
  8643. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8644. if (isset($category['attribs']['']['domain']))
  8645. {
  8646. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  8647. }
  8648. else
  8649. {
  8650. $scheme = null;
  8651. }
  8652. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  8653. }
  8654. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  8655. {
  8656. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  8657. }
  8658. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  8659. {
  8660. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  8661. }
  8662. if (!empty($categories))
  8663. {
  8664. return array_unique($categories);
  8665. }
  8666. else
  8667. {
  8668. return null;
  8669. }
  8670. }
  8671. /**
  8672. * Get an author for the item
  8673. *
  8674. * @since Beta 2
  8675. * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
  8676. * @return SimplePie_Author|null
  8677. */
  8678. public function get_author($key = 0)
  8679. {
  8680. $authors = $this->get_authors();
  8681. if (isset($authors[$key]))
  8682. {
  8683. return $authors[$key];
  8684. }
  8685. else
  8686. {
  8687. return null;
  8688. }
  8689. }
  8690. /**
  8691. * Get a contributor for the item
  8692. *
  8693. * @since 1.1
  8694. * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
  8695. * @return SimplePie_Author|null
  8696. */
  8697. public function get_contributor($key = 0)
  8698. {
  8699. $contributors = $this->get_contributors();
  8700. if (isset($contributors[$key]))
  8701. {
  8702. return $contributors[$key];
  8703. }
  8704. else
  8705. {
  8706. return null;
  8707. }
  8708. }
  8709. /**
  8710. * Get all contributors for the item
  8711. *
  8712. * Uses `<atom:contributor>`
  8713. *
  8714. * @since 1.1
  8715. * @return array|null List of {@see SimplePie_Author} objects
  8716. */
  8717. public function get_contributors()
  8718. {
  8719. $contributors = array();
  8720. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  8721. {
  8722. $name = null;
  8723. $uri = null;
  8724. $email = null;
  8725. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  8726. {
  8727. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8728. }
  8729. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  8730. {
  8731. $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]));
  8732. }
  8733. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  8734. {
  8735. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8736. }
  8737. if ($name !== null || $email !== null || $uri !== null)
  8738. {
  8739. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  8740. }
  8741. }
  8742. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  8743. {
  8744. $name = null;
  8745. $url = null;
  8746. $email = null;
  8747. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  8748. {
  8749. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8750. }
  8751. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  8752. {
  8753. $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]));
  8754. }
  8755. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  8756. {
  8757. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8758. }
  8759. if ($name !== null || $email !== null || $url !== null)
  8760. {
  8761. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  8762. }
  8763. }
  8764. if (!empty($contributors))
  8765. {
  8766. return array_unique($contributors);
  8767. }
  8768. else
  8769. {
  8770. return null;
  8771. }
  8772. }
  8773. /**
  8774. * Get all authors for the item
  8775. *
  8776. * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
  8777. *
  8778. * @since Beta 2
  8779. * @return array|null List of {@see SimplePie_Author} objects
  8780. */
  8781. public function get_authors()
  8782. {
  8783. $authors = array();
  8784. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  8785. {
  8786. $name = null;
  8787. $uri = null;
  8788. $email = null;
  8789. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  8790. {
  8791. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8792. }
  8793. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  8794. {
  8795. $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]));
  8796. }
  8797. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  8798. {
  8799. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8800. }
  8801. if ($name !== null || $email !== null || $uri !== null)
  8802. {
  8803. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  8804. }
  8805. }
  8806. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  8807. {
  8808. $name = null;
  8809. $url = null;
  8810. $email = null;
  8811. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  8812. {
  8813. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8814. }
  8815. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  8816. {
  8817. $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]));
  8818. }
  8819. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  8820. {
  8821. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8822. }
  8823. if ($name !== null || $email !== null || $url !== null)
  8824. {
  8825. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  8826. }
  8827. }
  8828. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
  8829. {
  8830. $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
  8831. }
  8832. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  8833. {
  8834. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  8835. }
  8836. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  8837. {
  8838. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  8839. }
  8840. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  8841. {
  8842. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  8843. }
  8844. if (!empty($authors))
  8845. {
  8846. return array_unique($authors);
  8847. }
  8848. elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
  8849. {
  8850. return $authors;
  8851. }
  8852. elseif ($authors = $this->feed->get_authors())
  8853. {
  8854. return $authors;
  8855. }
  8856. else
  8857. {
  8858. return null;
  8859. }
  8860. }
  8861. /**
  8862. * Get the copyright info for the item
  8863. *
  8864. * Uses `<atom:rights>` or `<dc:rights>`
  8865. *
  8866. * @since 1.1
  8867. * @return string
  8868. */
  8869. public function get_copyright()
  8870. {
  8871. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  8872. {
  8873. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  8874. }
  8875. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  8876. {
  8877. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8878. }
  8879. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  8880. {
  8881. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  8882. }
  8883. else
  8884. {
  8885. return null;
  8886. }
  8887. }
  8888. /**
  8889. * Get the posting date/time for the item
  8890. *
  8891. * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
  8892. * `<atom:modified>`, `<pubDate>` or `<dc:date>`
  8893. *
  8894. * Note: obeys PHP's timezone setting. To get a UTC date/time, use
  8895. * {@see get_gmdate}
  8896. *
  8897. * @since Beta 2 (previously called `get_item_date` since 0.8)
  8898. *
  8899. * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
  8900. * @return int|string|null
  8901. */
  8902. public function get_date($date_format = 'j F Y, g:i a')
  8903. {
  8904. if (!isset($this->data['date']))
  8905. {
  8906. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
  8907. {
  8908. $this->data['date']['raw'] = $return[0]['data'];
  8909. }
  8910. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
  8911. {
  8912. $this->data['date']['raw'] = $return[0]['data'];
  8913. }
  8914. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
  8915. {
  8916. $this->data['date']['raw'] = $return[0]['data'];
  8917. }
  8918. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
  8919. {
  8920. $this->data['date']['raw'] = $return[0]['data'];
  8921. }
  8922. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
  8923. {
  8924. $this->data['date']['raw'] = $return[0]['data'];
  8925. }
  8926. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
  8927. {
  8928. $this->data['date']['raw'] = $return[0]['data'];
  8929. }
  8930. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
  8931. {
  8932. $this->data['date']['raw'] = $return[0]['data'];
  8933. }
  8934. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
  8935. {
  8936. $this->data['date']['raw'] = $return[0]['data'];
  8937. }
  8938. if (!empty($this->data['date']['raw']))
  8939. {
  8940. $parser = $this->registry->call('Parse_Date', 'get');
  8941. $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
  8942. }
  8943. else
  8944. {
  8945. $this->data['date'] = null;
  8946. }
  8947. }
  8948. if ($this->data['date'])
  8949. {
  8950. $date_format = (string) $date_format;
  8951. switch ($date_format)
  8952. {
  8953. case '':
  8954. return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
  8955. case 'U':
  8956. return $this->data['date']['parsed'];
  8957. default:
  8958. return date($date_format, $this->data['date']['parsed']);
  8959. }
  8960. }
  8961. else
  8962. {
  8963. return null;
  8964. }
  8965. }
  8966. /**
  8967. * Get the update date/time for the item
  8968. *
  8969. * Uses `<atom:updated>`
  8970. *
  8971. * Note: obeys PHP's timezone setting. To get a UTC date/time, use
  8972. * {@see get_gmdate}
  8973. *
  8974. * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
  8975. * @return int|string|null
  8976. */
  8977. public function get_updated_date($date_format = 'j F Y, g:i a')
  8978. {
  8979. if (!isset($this->data['updated']))
  8980. {
  8981. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
  8982. {
  8983. $this->data['updated']['raw'] = $return[0]['data'];
  8984. }
  8985. if (!empty($this->data['updated']['raw']))
  8986. {
  8987. $parser = $this->registry->call('Parse_Date', 'get');
  8988. $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
  8989. }
  8990. else
  8991. {
  8992. $this->data['updated'] = null;
  8993. }
  8994. }
  8995. if ($this->data['updated'])
  8996. {
  8997. $date_format = (string) $date_format;
  8998. switch ($date_format)
  8999. {
  9000. case '':
  9001. return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
  9002. case 'U':
  9003. return $this->data['updated']['parsed'];
  9004. default:
  9005. return date($date_format, $this->data['updated']['parsed']);
  9006. }
  9007. }
  9008. else
  9009. {
  9010. return null;
  9011. }
  9012. }
  9013. /**
  9014. * Get the localized posting date/time for the item
  9015. *
  9016. * Returns the date formatted in the localized language. To display in
  9017. * languages other than the server's default, you need to change the locale
  9018. * with {@link http://php.net/setlocale setlocale()}. The available
  9019. * localizations depend on which ones are installed on your web server.
  9020. *
  9021. * @since 1.0
  9022. *
  9023. * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
  9024. * @return int|string|null
  9025. */
  9026. public function get_local_date($date_format = '%c')
  9027. {
  9028. if (!$date_format)
  9029. {
  9030. return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
  9031. }
  9032. elseif (($date = $this->get_date('U')) !== null && $date !== false)
  9033. {
  9034. return strftime($date_format, $date);
  9035. }
  9036. else
  9037. {
  9038. return null;
  9039. }
  9040. }
  9041. /**
  9042. * Get the posting date/time for the item (UTC time)
  9043. *
  9044. * @see get_date
  9045. * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
  9046. * @return int|string|null
  9047. */
  9048. public function get_gmdate($date_format = 'j F Y, g:i a')
  9049. {
  9050. $date = $this->get_date('U');
  9051. if ($date === null)
  9052. {
  9053. return null;
  9054. }
  9055. return gmdate($date_format, $date);
  9056. }
  9057. /**
  9058. * Get the update date/time for the item (UTC time)
  9059. *
  9060. * @see get_updated_date
  9061. * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
  9062. * @return int|string|null
  9063. */
  9064. public function get_updated_gmdate($date_format = 'j F Y, g:i a')
  9065. {
  9066. $date = $this->get_updated_date('U');
  9067. if ($date === null)
  9068. {
  9069. return null;
  9070. }
  9071. return gmdate($date_format, $date);
  9072. }
  9073. /**
  9074. * Get the permalink for the item
  9075. *
  9076. * Returns the first link available with a relationship of "alternate".
  9077. * Identical to {@see get_link()} with key 0
  9078. *
  9079. * @see get_link
  9080. * @since 0.8
  9081. * @return string|null Permalink URL
  9082. */
  9083. public function get_permalink()
  9084. {
  9085. $link = $this->get_link();
  9086. $enclosure = $this->get_enclosure(0);
  9087. if ($link !== null)
  9088. {
  9089. return $link;
  9090. }
  9091. elseif ($enclosure !== null)
  9092. {
  9093. return $enclosure->get_link();
  9094. }
  9095. else
  9096. {
  9097. return null;
  9098. }
  9099. }
  9100. /**
  9101. * Get a single link for the item
  9102. *
  9103. * @since Beta 3
  9104. * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
  9105. * @param string $rel The relationship of the link to return
  9106. * @return string|null Link URL
  9107. */
  9108. public function get_link($key = 0, $rel = 'alternate')
  9109. {
  9110. $links = $this->get_links($rel);
  9111. if ($links[$key] !== null)
  9112. {
  9113. return $links[$key];
  9114. }
  9115. else
  9116. {
  9117. return null;
  9118. }
  9119. }
  9120. /**
  9121. * Get all links for the item
  9122. *
  9123. * Uses `<atom:link>`, `<link>` or `<guid>`
  9124. *
  9125. * @since Beta 2
  9126. * @param string $rel The relationship of links to return
  9127. * @return array|null Links found for the item (strings)
  9128. */
  9129. public function get_links($rel = 'alternate')
  9130. {
  9131. if (!isset($this->data['links']))
  9132. {
  9133. $this->data['links'] = array();
  9134. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  9135. {
  9136. if (isset($link['attribs']['']['href']))
  9137. {
  9138. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  9139. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  9140. }
  9141. }
  9142. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  9143. {
  9144. if (isset($link['attribs']['']['href']))
  9145. {
  9146. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  9147. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  9148. }
  9149. }
  9150. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  9151. {
  9152. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  9153. }
  9154. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  9155. {
  9156. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  9157. }
  9158. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  9159. {
  9160. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  9161. }
  9162. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  9163. {
  9164. if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
  9165. {
  9166. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  9167. }
  9168. }
  9169. $keys = array_keys($this->data['links']);
  9170. foreach ($keys as $key)
  9171. {
  9172. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  9173. {
  9174. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  9175. {
  9176. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  9177. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  9178. }
  9179. else
  9180. {
  9181. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  9182. }
  9183. }
  9184. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  9185. {
  9186. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  9187. }
  9188. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  9189. }
  9190. }
  9191. if (isset($this->data['links'][$rel]))
  9192. {
  9193. return $this->data['links'][$rel];
  9194. }
  9195. else
  9196. {
  9197. return null;
  9198. }
  9199. }
  9200. /**
  9201. * Get an enclosure from the item
  9202. *
  9203. * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
  9204. *
  9205. * @since Beta 2
  9206. * @todo Add ability to prefer one type of content over another (in a media group).
  9207. * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
  9208. * @return SimplePie_Enclosure|null
  9209. */
  9210. public function get_enclosure($key = 0, $prefer = null)
  9211. {
  9212. $enclosures = $this->get_enclosures();
  9213. if (isset($enclosures[$key]))
  9214. {
  9215. return $enclosures[$key];
  9216. }
  9217. else
  9218. {
  9219. return null;
  9220. }
  9221. }
  9222. /**
  9223. * Get all available enclosures (podcasts, etc.)
  9224. *
  9225. * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
  9226. *
  9227. * At this point, we're pretty much assuming that all enclosures for an item
  9228. * are the same content. Anything else is too complicated to
  9229. * properly support.
  9230. *
  9231. * @since Beta 2
  9232. * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
  9233. * @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).
  9234. * @return array|null List of SimplePie_Enclosure items
  9235. */
  9236. public function get_enclosures()
  9237. {
  9238. if (!isset($this->data['enclosures']))
  9239. {
  9240. $this->data['enclosures'] = array();
  9241. // Elements
  9242. $captions_parent = null;
  9243. $categories_parent = null;
  9244. $copyrights_parent = null;
  9245. $credits_parent = null;
  9246. $description_parent = null;
  9247. $duration_parent = null;
  9248. $hashes_parent = null;
  9249. $keywords_parent = null;
  9250. $player_parent = null;
  9251. $ratings_parent = null;
  9252. $restrictions_parent = null;
  9253. $thumbnails_parent = null;
  9254. $title_parent = null;
  9255. // Let's do the channel and item-level ones first, and just re-use them if we need to.
  9256. $parent = $this->get_feed();
  9257. // CAPTIONS
  9258. if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
  9259. {
  9260. foreach ($captions as $caption)
  9261. {
  9262. $caption_type = null;
  9263. $caption_lang = null;
  9264. $caption_startTime = null;
  9265. $caption_endTime = null;
  9266. $caption_text = null;
  9267. if (isset($caption['attribs']['']['type']))
  9268. {
  9269. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  9270. }
  9271. if (isset($caption['attribs']['']['lang']))
  9272. {
  9273. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  9274. }
  9275. if (isset($caption['attribs']['']['start']))
  9276. {
  9277. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  9278. }
  9279. if (isset($caption['attribs']['']['end']))
  9280. {
  9281. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  9282. }
  9283. if (isset($caption['data']))
  9284. {
  9285. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9286. }
  9287. $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  9288. }
  9289. }
  9290. elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
  9291. {
  9292. foreach ($captions as $caption)
  9293. {
  9294. $caption_type = null;
  9295. $caption_lang = null;
  9296. $caption_startTime = null;
  9297. $caption_endTime = null;
  9298. $caption_text = null;
  9299. if (isset($caption['attribs']['']['type']))
  9300. {
  9301. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  9302. }
  9303. if (isset($caption['attribs']['']['lang']))
  9304. {
  9305. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  9306. }
  9307. if (isset($caption['attribs']['']['start']))
  9308. {
  9309. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  9310. }
  9311. if (isset($caption['attribs']['']['end']))
  9312. {
  9313. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  9314. }
  9315. if (isset($caption['data']))
  9316. {
  9317. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9318. }
  9319. $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  9320. }
  9321. }
  9322. if (is_array($captions_parent))
  9323. {
  9324. $captions_parent = array_values(array_unique($captions_parent));
  9325. }
  9326. // CATEGORIES
  9327. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
  9328. {
  9329. $term = null;
  9330. $scheme = null;
  9331. $label = null;
  9332. if (isset($category['data']))
  9333. {
  9334. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9335. }
  9336. if (isset($category['attribs']['']['scheme']))
  9337. {
  9338. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9339. }
  9340. else
  9341. {
  9342. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  9343. }
  9344. if (isset($category['attribs']['']['label']))
  9345. {
  9346. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  9347. }
  9348. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  9349. }
  9350. foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
  9351. {
  9352. $term = null;
  9353. $scheme = null;
  9354. $label = null;
  9355. if (isset($category['data']))
  9356. {
  9357. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9358. }
  9359. if (isset($category['attribs']['']['scheme']))
  9360. {
  9361. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9362. }
  9363. else
  9364. {
  9365. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  9366. }
  9367. if (isset($category['attribs']['']['label']))
  9368. {
  9369. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  9370. }
  9371. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  9372. }
  9373. foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
  9374. {
  9375. $term = null;
  9376. $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
  9377. $label = null;
  9378. if (isset($category['attribs']['']['text']))
  9379. {
  9380. $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
  9381. }
  9382. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  9383. if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
  9384. {
  9385. foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
  9386. {
  9387. if (isset($subcategory['attribs']['']['text']))
  9388. {
  9389. $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
  9390. }
  9391. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  9392. }
  9393. }
  9394. }
  9395. if (is_array($categories_parent))
  9396. {
  9397. $categories_parent = array_values(array_unique($categories_parent));
  9398. }
  9399. // COPYRIGHT
  9400. if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
  9401. {
  9402. $copyright_url = null;
  9403. $copyright_label = null;
  9404. if (isset($copyright[0]['attribs']['']['url']))
  9405. {
  9406. $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  9407. }
  9408. if (isset($copyright[0]['data']))
  9409. {
  9410. $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9411. }
  9412. $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  9413. }
  9414. elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
  9415. {
  9416. $copyright_url = null;
  9417. $copyright_label = null;
  9418. if (isset($copyright[0]['attribs']['']['url']))
  9419. {
  9420. $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  9421. }
  9422. if (isset($copyright[0]['data']))
  9423. {
  9424. $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9425. }
  9426. $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  9427. }
  9428. // CREDITS
  9429. if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
  9430. {
  9431. foreach ($credits as $credit)
  9432. {
  9433. $credit_role = null;
  9434. $credit_scheme = null;
  9435. $credit_name = null;
  9436. if (isset($credit['attribs']['']['role']))
  9437. {
  9438. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  9439. }
  9440. if (isset($credit['attribs']['']['scheme']))
  9441. {
  9442. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9443. }
  9444. else
  9445. {
  9446. $credit_scheme = 'urn:ebu';
  9447. }
  9448. if (isset($credit['data']))
  9449. {
  9450. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9451. }
  9452. $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  9453. }
  9454. }
  9455. elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
  9456. {
  9457. foreach ($credits as $credit)
  9458. {
  9459. $credit_role = null;
  9460. $credit_scheme = null;
  9461. $credit_name = null;
  9462. if (isset($credit['attribs']['']['role']))
  9463. {
  9464. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  9465. }
  9466. if (isset($credit['attribs']['']['scheme']))
  9467. {
  9468. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9469. }
  9470. else
  9471. {
  9472. $credit_scheme = 'urn:ebu';
  9473. }
  9474. if (isset($credit['data']))
  9475. {
  9476. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9477. }
  9478. $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  9479. }
  9480. }
  9481. if (is_array($credits_parent))
  9482. {
  9483. $credits_parent = array_values(array_unique($credits_parent));
  9484. }
  9485. // DESCRIPTION
  9486. if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
  9487. {
  9488. if (isset($description_parent[0]['data']))
  9489. {
  9490. $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9491. }
  9492. }
  9493. elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
  9494. {
  9495. if (isset($description_parent[0]['data']))
  9496. {
  9497. $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9498. }
  9499. }
  9500. // DURATION
  9501. if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
  9502. {
  9503. $seconds = null;
  9504. $minutes = null;
  9505. $hours = null;
  9506. if (isset($duration_parent[0]['data']))
  9507. {
  9508. $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  9509. if (sizeof($temp) > 0)
  9510. {
  9511. $seconds = (int) array_pop($temp);
  9512. }
  9513. if (sizeof($temp) > 0)
  9514. {
  9515. $minutes = (int) array_pop($temp);
  9516. $seconds += $minutes * 60;
  9517. }
  9518. if (sizeof($temp) > 0)
  9519. {
  9520. $hours = (int) array_pop($temp);
  9521. $seconds += $hours * 3600;
  9522. }
  9523. unset($temp);
  9524. $duration_parent = $seconds;
  9525. }
  9526. }
  9527. // HASHES
  9528. if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
  9529. {
  9530. foreach ($hashes_iterator as $hash)
  9531. {
  9532. $value = null;
  9533. $algo = null;
  9534. if (isset($hash['data']))
  9535. {
  9536. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9537. }
  9538. if (isset($hash['attribs']['']['algo']))
  9539. {
  9540. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  9541. }
  9542. else
  9543. {
  9544. $algo = 'md5';
  9545. }
  9546. $hashes_parent[] = $algo.':'.$value;
  9547. }
  9548. }
  9549. elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
  9550. {
  9551. foreach ($hashes_iterator as $hash)
  9552. {
  9553. $value = null;
  9554. $algo = null;
  9555. if (isset($hash['data']))
  9556. {
  9557. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9558. }
  9559. if (isset($hash['attribs']['']['algo']))
  9560. {
  9561. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  9562. }
  9563. else
  9564. {
  9565. $algo = 'md5';
  9566. }
  9567. $hashes_parent[] = $algo.':'.$value;
  9568. }
  9569. }
  9570. if (is_array($hashes_parent))
  9571. {
  9572. $hashes_parent = array_values(array_unique($hashes_parent));
  9573. }
  9574. // KEYWORDS
  9575. if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
  9576. {
  9577. if (isset($keywords[0]['data']))
  9578. {
  9579. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  9580. foreach ($temp as $word)
  9581. {
  9582. $keywords_parent[] = trim($word);
  9583. }
  9584. }
  9585. unset($temp);
  9586. }
  9587. elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
  9588. {
  9589. if (isset($keywords[0]['data']))
  9590. {
  9591. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  9592. foreach ($temp as $word)
  9593. {
  9594. $keywords_parent[] = trim($word);
  9595. }
  9596. }
  9597. unset($temp);
  9598. }
  9599. elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
  9600. {
  9601. if (isset($keywords[0]['data']))
  9602. {
  9603. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  9604. foreach ($temp as $word)
  9605. {
  9606. $keywords_parent[] = trim($word);
  9607. }
  9608. }
  9609. unset($temp);
  9610. }
  9611. elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
  9612. {
  9613. if (isset($keywords[0]['data']))
  9614. {
  9615. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  9616. foreach ($temp as $word)
  9617. {
  9618. $keywords_parent[] = trim($word);
  9619. }
  9620. }
  9621. unset($temp);
  9622. }
  9623. if (is_array($keywords_parent))
  9624. {
  9625. $keywords_parent = array_values(array_unique($keywords_parent));
  9626. }
  9627. // PLAYER
  9628. if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
  9629. {
  9630. if (isset($player_parent[0]['attribs']['']['url']))
  9631. {
  9632. $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  9633. }
  9634. }
  9635. elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
  9636. {
  9637. if (isset($player_parent[0]['attribs']['']['url']))
  9638. {
  9639. $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  9640. }
  9641. }
  9642. // RATINGS
  9643. if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
  9644. {
  9645. foreach ($ratings as $rating)
  9646. {
  9647. $rating_scheme = null;
  9648. $rating_value = null;
  9649. if (isset($rating['attribs']['']['scheme']))
  9650. {
  9651. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9652. }
  9653. else
  9654. {
  9655. $rating_scheme = 'urn:simple';
  9656. }
  9657. if (isset($rating['data']))
  9658. {
  9659. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9660. }
  9661. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  9662. }
  9663. }
  9664. elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
  9665. {
  9666. foreach ($ratings as $rating)
  9667. {
  9668. $rating_scheme = 'urn:itunes';
  9669. $rating_value = null;
  9670. if (isset($rating['data']))
  9671. {
  9672. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9673. }
  9674. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  9675. }
  9676. }
  9677. elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
  9678. {
  9679. foreach ($ratings as $rating)
  9680. {
  9681. $rating_scheme = null;
  9682. $rating_value = null;
  9683. if (isset($rating['attribs']['']['scheme']))
  9684. {
  9685. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9686. }
  9687. else
  9688. {
  9689. $rating_scheme = 'urn:simple';
  9690. }
  9691. if (isset($rating['data']))
  9692. {
  9693. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9694. }
  9695. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  9696. }
  9697. }
  9698. elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
  9699. {
  9700. foreach ($ratings as $rating)
  9701. {
  9702. $rating_scheme = 'urn:itunes';
  9703. $rating_value = null;
  9704. if (isset($rating['data']))
  9705. {
  9706. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9707. }
  9708. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  9709. }
  9710. }
  9711. if (is_array($ratings_parent))
  9712. {
  9713. $ratings_parent = array_values(array_unique($ratings_parent));
  9714. }
  9715. // RESTRICTIONS
  9716. if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
  9717. {
  9718. foreach ($restrictions as $restriction)
  9719. {
  9720. $restriction_relationship = null;
  9721. $restriction_type = null;
  9722. $restriction_value = null;
  9723. if (isset($restriction['attribs']['']['relationship']))
  9724. {
  9725. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  9726. }
  9727. if (isset($restriction['attribs']['']['type']))
  9728. {
  9729. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  9730. }
  9731. if (isset($restriction['data']))
  9732. {
  9733. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9734. }
  9735. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  9736. }
  9737. }
  9738. elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
  9739. {
  9740. foreach ($restrictions as $restriction)
  9741. {
  9742. $restriction_relationship = 'allow';
  9743. $restriction_type = null;
  9744. $restriction_value = 'itunes';
  9745. if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
  9746. {
  9747. $restriction_relationship = 'deny';
  9748. }
  9749. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  9750. }
  9751. }
  9752. elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
  9753. {
  9754. foreach ($restrictions as $restriction)
  9755. {
  9756. $restriction_relationship = null;
  9757. $restriction_type = null;
  9758. $restriction_value = null;
  9759. if (isset($restriction['attribs']['']['relationship']))
  9760. {
  9761. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  9762. }
  9763. if (isset($restriction['attribs']['']['type']))
  9764. {
  9765. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  9766. }
  9767. if (isset($restriction['data']))
  9768. {
  9769. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9770. }
  9771. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  9772. }
  9773. }
  9774. elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
  9775. {
  9776. foreach ($restrictions as $restriction)
  9777. {
  9778. $restriction_relationship = 'allow';
  9779. $restriction_type = null;
  9780. $restriction_value = 'itunes';
  9781. if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
  9782. {
  9783. $restriction_relationship = 'deny';
  9784. }
  9785. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  9786. }
  9787. }
  9788. if (is_array($restrictions_parent))
  9789. {
  9790. $restrictions_parent = array_values(array_unique($restrictions_parent));
  9791. }
  9792. else
  9793. {
  9794. $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
  9795. }
  9796. // THUMBNAILS
  9797. if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
  9798. {
  9799. foreach ($thumbnails as $thumbnail)
  9800. {
  9801. if (isset($thumbnail['attribs']['']['url']))
  9802. {
  9803. $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  9804. }
  9805. }
  9806. }
  9807. elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
  9808. {
  9809. foreach ($thumbnails as $thumbnail)
  9810. {
  9811. if (isset($thumbnail['attribs']['']['url']))
  9812. {
  9813. $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  9814. }
  9815. }
  9816. }
  9817. // TITLES
  9818. if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
  9819. {
  9820. if (isset($title_parent[0]['data']))
  9821. {
  9822. $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9823. }
  9824. }
  9825. elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
  9826. {
  9827. if (isset($title_parent[0]['data']))
  9828. {
  9829. $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9830. }
  9831. }
  9832. // Clear the memory
  9833. unset($parent);
  9834. // Attributes
  9835. $bitrate = null;
  9836. $channels = null;
  9837. $duration = null;
  9838. $expression = null;
  9839. $framerate = null;
  9840. $height = null;
  9841. $javascript = null;
  9842. $lang = null;
  9843. $length = null;
  9844. $medium = null;
  9845. $samplingrate = null;
  9846. $type = null;
  9847. $url = null;
  9848. $width = null;
  9849. // Elements
  9850. $captions = null;
  9851. $categories = null;
  9852. $copyrights = null;
  9853. $credits = null;
  9854. $description = null;
  9855. $hashes = null;
  9856. $keywords = null;
  9857. $player = null;
  9858. $ratings = null;
  9859. $restrictions = null;
  9860. $thumbnails = null;
  9861. $title = null;
  9862. // If we have media:group tags, loop through them.
  9863. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
  9864. {
  9865. if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
  9866. {
  9867. // If we have media:content tags, loop through them.
  9868. foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
  9869. {
  9870. if (isset($content['attribs']['']['url']))
  9871. {
  9872. // Attributes
  9873. $bitrate = null;
  9874. $channels = null;
  9875. $duration = null;
  9876. $expression = null;
  9877. $framerate = null;
  9878. $height = null;
  9879. $javascript = null;
  9880. $lang = null;
  9881. $length = null;
  9882. $medium = null;
  9883. $samplingrate = null;
  9884. $type = null;
  9885. $url = null;
  9886. $width = null;
  9887. // Elements
  9888. $captions = null;
  9889. $categories = null;
  9890. $copyrights = null;
  9891. $credits = null;
  9892. $description = null;
  9893. $hashes = null;
  9894. $keywords = null;
  9895. $player = null;
  9896. $ratings = null;
  9897. $restrictions = null;
  9898. $thumbnails = null;
  9899. $title = null;
  9900. // Start checking the attributes of media:content
  9901. if (isset($content['attribs']['']['bitrate']))
  9902. {
  9903. $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  9904. }
  9905. if (isset($content['attribs']['']['channels']))
  9906. {
  9907. $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
  9908. }
  9909. if (isset($content['attribs']['']['duration']))
  9910. {
  9911. $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
  9912. }
  9913. else
  9914. {
  9915. $duration = $duration_parent;
  9916. }
  9917. if (isset($content['attribs']['']['expression']))
  9918. {
  9919. $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
  9920. }
  9921. if (isset($content['attribs']['']['framerate']))
  9922. {
  9923. $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
  9924. }
  9925. if (isset($content['attribs']['']['height']))
  9926. {
  9927. $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
  9928. }
  9929. if (isset($content['attribs']['']['lang']))
  9930. {
  9931. $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  9932. }
  9933. if (isset($content['attribs']['']['fileSize']))
  9934. {
  9935. $length = ceil($content['attribs']['']['fileSize']);
  9936. }
  9937. if (isset($content['attribs']['']['medium']))
  9938. {
  9939. $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
  9940. }
  9941. if (isset($content['attribs']['']['samplingrate']))
  9942. {
  9943. $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  9944. }
  9945. if (isset($content['attribs']['']['type']))
  9946. {
  9947. $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  9948. }
  9949. if (isset($content['attribs']['']['width']))
  9950. {
  9951. $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
  9952. }
  9953. $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  9954. // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
  9955. // CAPTIONS
  9956. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  9957. {
  9958. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  9959. {
  9960. $caption_type = null;
  9961. $caption_lang = null;
  9962. $caption_startTime = null;
  9963. $caption_endTime = null;
  9964. $caption_text = null;
  9965. if (isset($caption['attribs']['']['type']))
  9966. {
  9967. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  9968. }
  9969. if (isset($caption['attribs']['']['lang']))
  9970. {
  9971. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  9972. }
  9973. if (isset($caption['attribs']['']['start']))
  9974. {
  9975. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  9976. }
  9977. if (isset($caption['attribs']['']['end']))
  9978. {
  9979. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  9980. }
  9981. if (isset($caption['data']))
  9982. {
  9983. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9984. }
  9985. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  9986. }
  9987. if (is_array($captions))
  9988. {
  9989. $captions = array_values(array_unique($captions));
  9990. }
  9991. }
  9992. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  9993. {
  9994. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  9995. {
  9996. $caption_type = null;
  9997. $caption_lang = null;
  9998. $caption_startTime = null;
  9999. $caption_endTime = null;
  10000. $caption_text = null;
  10001. if (isset($caption['attribs']['']['type']))
  10002. {
  10003. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10004. }
  10005. if (isset($caption['attribs']['']['lang']))
  10006. {
  10007. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  10008. }
  10009. if (isset($caption['attribs']['']['start']))
  10010. {
  10011. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  10012. }
  10013. if (isset($caption['attribs']['']['end']))
  10014. {
  10015. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  10016. }
  10017. if (isset($caption['data']))
  10018. {
  10019. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10020. }
  10021. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  10022. }
  10023. if (is_array($captions))
  10024. {
  10025. $captions = array_values(array_unique($captions));
  10026. }
  10027. }
  10028. else
  10029. {
  10030. $captions = $captions_parent;
  10031. }
  10032. // CATEGORIES
  10033. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  10034. {
  10035. foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  10036. {
  10037. $term = null;
  10038. $scheme = null;
  10039. $label = null;
  10040. if (isset($category['data']))
  10041. {
  10042. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10043. }
  10044. if (isset($category['attribs']['']['scheme']))
  10045. {
  10046. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10047. }
  10048. else
  10049. {
  10050. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  10051. }
  10052. if (isset($category['attribs']['']['label']))
  10053. {
  10054. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  10055. }
  10056. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  10057. }
  10058. }
  10059. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  10060. {
  10061. foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  10062. {
  10063. $term = null;
  10064. $scheme = null;
  10065. $label = null;
  10066. if (isset($category['data']))
  10067. {
  10068. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10069. }
  10070. if (isset($category['attribs']['']['scheme']))
  10071. {
  10072. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10073. }
  10074. else
  10075. {
  10076. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  10077. }
  10078. if (isset($category['attribs']['']['label']))
  10079. {
  10080. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  10081. }
  10082. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  10083. }
  10084. }
  10085. if (is_array($categories) && is_array($categories_parent))
  10086. {
  10087. $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
  10088. }
  10089. elseif (is_array($categories))
  10090. {
  10091. $categories = array_values(array_unique($categories));
  10092. }
  10093. elseif (is_array($categories_parent))
  10094. {
  10095. $categories = array_values(array_unique($categories_parent));
  10096. }
  10097. // COPYRIGHTS
  10098. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  10099. {
  10100. $copyright_url = null;
  10101. $copyright_label = null;
  10102. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  10103. {
  10104. $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  10105. }
  10106. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  10107. {
  10108. $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10109. }
  10110. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  10111. }
  10112. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  10113. {
  10114. $copyright_url = null;
  10115. $copyright_label = null;
  10116. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  10117. {
  10118. $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  10119. }
  10120. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  10121. {
  10122. $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10123. }
  10124. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  10125. }
  10126. else
  10127. {
  10128. $copyrights = $copyrights_parent;
  10129. }
  10130. // CREDITS
  10131. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  10132. {
  10133. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  10134. {
  10135. $credit_role = null;
  10136. $credit_scheme = null;
  10137. $credit_name = null;
  10138. if (isset($credit['attribs']['']['role']))
  10139. {
  10140. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  10141. }
  10142. if (isset($credit['attribs']['']['scheme']))
  10143. {
  10144. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10145. }
  10146. else
  10147. {
  10148. $credit_scheme = 'urn:ebu';
  10149. }
  10150. if (isset($credit['data']))
  10151. {
  10152. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10153. }
  10154. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  10155. }
  10156. if (is_array($credits))
  10157. {
  10158. $credits = array_values(array_unique($credits));
  10159. }
  10160. }
  10161. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  10162. {
  10163. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  10164. {
  10165. $credit_role = null;
  10166. $credit_scheme = null;
  10167. $credit_name = null;
  10168. if (isset($credit['attribs']['']['role']))
  10169. {
  10170. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  10171. }
  10172. if (isset($credit['attribs']['']['scheme']))
  10173. {
  10174. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10175. }
  10176. else
  10177. {
  10178. $credit_scheme = 'urn:ebu';
  10179. }
  10180. if (isset($credit['data']))
  10181. {
  10182. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10183. }
  10184. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  10185. }
  10186. if (is_array($credits))
  10187. {
  10188. $credits = array_values(array_unique($credits));
  10189. }
  10190. }
  10191. else
  10192. {
  10193. $credits = $credits_parent;
  10194. }
  10195. // DESCRIPTION
  10196. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  10197. {
  10198. $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10199. }
  10200. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  10201. {
  10202. $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10203. }
  10204. else
  10205. {
  10206. $description = $description_parent;
  10207. }
  10208. // HASHES
  10209. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  10210. {
  10211. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  10212. {
  10213. $value = null;
  10214. $algo = null;
  10215. if (isset($hash['data']))
  10216. {
  10217. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10218. }
  10219. if (isset($hash['attribs']['']['algo']))
  10220. {
  10221. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  10222. }
  10223. else
  10224. {
  10225. $algo = 'md5';
  10226. }
  10227. $hashes[] = $algo.':'.$value;
  10228. }
  10229. if (is_array($hashes))
  10230. {
  10231. $hashes = array_values(array_unique($hashes));
  10232. }
  10233. }
  10234. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  10235. {
  10236. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  10237. {
  10238. $value = null;
  10239. $algo = null;
  10240. if (isset($hash['data']))
  10241. {
  10242. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10243. }
  10244. if (isset($hash['attribs']['']['algo']))
  10245. {
  10246. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  10247. }
  10248. else
  10249. {
  10250. $algo = 'md5';
  10251. }
  10252. $hashes[] = $algo.':'.$value;
  10253. }
  10254. if (is_array($hashes))
  10255. {
  10256. $hashes = array_values(array_unique($hashes));
  10257. }
  10258. }
  10259. else
  10260. {
  10261. $hashes = $hashes_parent;
  10262. }
  10263. // KEYWORDS
  10264. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  10265. {
  10266. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  10267. {
  10268. $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10269. foreach ($temp as $word)
  10270. {
  10271. $keywords[] = trim($word);
  10272. }
  10273. unset($temp);
  10274. }
  10275. if (is_array($keywords))
  10276. {
  10277. $keywords = array_values(array_unique($keywords));
  10278. }
  10279. }
  10280. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  10281. {
  10282. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  10283. {
  10284. $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10285. foreach ($temp as $word)
  10286. {
  10287. $keywords[] = trim($word);
  10288. }
  10289. unset($temp);
  10290. }
  10291. if (is_array($keywords))
  10292. {
  10293. $keywords = array_values(array_unique($keywords));
  10294. }
  10295. }
  10296. else
  10297. {
  10298. $keywords = $keywords_parent;
  10299. }
  10300. // PLAYER
  10301. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  10302. {
  10303. $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10304. }
  10305. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  10306. {
  10307. $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10308. }
  10309. else
  10310. {
  10311. $player = $player_parent;
  10312. }
  10313. // RATINGS
  10314. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  10315. {
  10316. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  10317. {
  10318. $rating_scheme = null;
  10319. $rating_value = null;
  10320. if (isset($rating['attribs']['']['scheme']))
  10321. {
  10322. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10323. }
  10324. else
  10325. {
  10326. $rating_scheme = 'urn:simple';
  10327. }
  10328. if (isset($rating['data']))
  10329. {
  10330. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10331. }
  10332. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10333. }
  10334. if (is_array($ratings))
  10335. {
  10336. $ratings = array_values(array_unique($ratings));
  10337. }
  10338. }
  10339. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  10340. {
  10341. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  10342. {
  10343. $rating_scheme = null;
  10344. $rating_value = null;
  10345. if (isset($rating['attribs']['']['scheme']))
  10346. {
  10347. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10348. }
  10349. else
  10350. {
  10351. $rating_scheme = 'urn:simple';
  10352. }
  10353. if (isset($rating['data']))
  10354. {
  10355. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10356. }
  10357. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10358. }
  10359. if (is_array($ratings))
  10360. {
  10361. $ratings = array_values(array_unique($ratings));
  10362. }
  10363. }
  10364. else
  10365. {
  10366. $ratings = $ratings_parent;
  10367. }
  10368. // RESTRICTIONS
  10369. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  10370. {
  10371. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  10372. {
  10373. $restriction_relationship = null;
  10374. $restriction_type = null;
  10375. $restriction_value = null;
  10376. if (isset($restriction['attribs']['']['relationship']))
  10377. {
  10378. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  10379. }
  10380. if (isset($restriction['attribs']['']['type']))
  10381. {
  10382. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10383. }
  10384. if (isset($restriction['data']))
  10385. {
  10386. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10387. }
  10388. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10389. }
  10390. if (is_array($restrictions))
  10391. {
  10392. $restrictions = array_values(array_unique($restrictions));
  10393. }
  10394. }
  10395. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  10396. {
  10397. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  10398. {
  10399. $restriction_relationship = null;
  10400. $restriction_type = null;
  10401. $restriction_value = null;
  10402. if (isset($restriction['attribs']['']['relationship']))
  10403. {
  10404. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  10405. }
  10406. if (isset($restriction['attribs']['']['type']))
  10407. {
  10408. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10409. }
  10410. if (isset($restriction['data']))
  10411. {
  10412. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10413. }
  10414. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10415. }
  10416. if (is_array($restrictions))
  10417. {
  10418. $restrictions = array_values(array_unique($restrictions));
  10419. }
  10420. }
  10421. else
  10422. {
  10423. $restrictions = $restrictions_parent;
  10424. }
  10425. // THUMBNAILS
  10426. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  10427. {
  10428. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  10429. {
  10430. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10431. }
  10432. if (is_array($thumbnails))
  10433. {
  10434. $thumbnails = array_values(array_unique($thumbnails));
  10435. }
  10436. }
  10437. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  10438. {
  10439. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  10440. {
  10441. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10442. }
  10443. if (is_array($thumbnails))
  10444. {
  10445. $thumbnails = array_values(array_unique($thumbnails));
  10446. }
  10447. }
  10448. else
  10449. {
  10450. $thumbnails = $thumbnails_parent;
  10451. }
  10452. // TITLES
  10453. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  10454. {
  10455. $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10456. }
  10457. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  10458. {
  10459. $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10460. }
  10461. else
  10462. {
  10463. $title = $title_parent;
  10464. }
  10465. $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));
  10466. }
  10467. }
  10468. }
  10469. }
  10470. // If we have standalone media:content tags, loop through them.
  10471. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
  10472. {
  10473. foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
  10474. {
  10475. if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  10476. {
  10477. // Attributes
  10478. $bitrate = null;
  10479. $channels = null;
  10480. $duration = null;
  10481. $expression = null;
  10482. $framerate = null;
  10483. $height = null;
  10484. $javascript = null;
  10485. $lang = null;
  10486. $length = null;
  10487. $medium = null;
  10488. $samplingrate = null;
  10489. $type = null;
  10490. $url = null;
  10491. $width = null;
  10492. // Elements
  10493. $captions = null;
  10494. $categories = null;
  10495. $copyrights = null;
  10496. $credits = null;
  10497. $description = null;
  10498. $hashes = null;
  10499. $keywords = null;
  10500. $player = null;
  10501. $ratings = null;
  10502. $restrictions = null;
  10503. $thumbnails = null;
  10504. $title = null;
  10505. // Start checking the attributes of media:content
  10506. if (isset($content['attribs']['']['bitrate']))
  10507. {
  10508. $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  10509. }
  10510. if (isset($content['attribs']['']['channels']))
  10511. {
  10512. $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
  10513. }
  10514. if (isset($content['attribs']['']['duration']))
  10515. {
  10516. $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
  10517. }
  10518. else
  10519. {
  10520. $duration = $duration_parent;
  10521. }
  10522. if (isset($content['attribs']['']['expression']))
  10523. {
  10524. $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
  10525. }
  10526. if (isset($content['attribs']['']['framerate']))
  10527. {
  10528. $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
  10529. }
  10530. if (isset($content['attribs']['']['height']))
  10531. {
  10532. $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
  10533. }
  10534. if (isset($content['attribs']['']['lang']))
  10535. {
  10536. $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  10537. }
  10538. if (isset($content['attribs']['']['fileSize']))
  10539. {
  10540. $length = ceil($content['attribs']['']['fileSize']);
  10541. }
  10542. if (isset($content['attribs']['']['medium']))
  10543. {
  10544. $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
  10545. }
  10546. if (isset($content['attribs']['']['samplingrate']))
  10547. {
  10548. $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  10549. }
  10550. if (isset($content['attribs']['']['type']))
  10551. {
  10552. $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10553. }
  10554. if (isset($content['attribs']['']['width']))
  10555. {
  10556. $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
  10557. }
  10558. if (isset($content['attribs']['']['url']))
  10559. {
  10560. $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10561. }
  10562. // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
  10563. // CAPTIONS
  10564. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  10565. {
  10566. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  10567. {
  10568. $caption_type = null;
  10569. $caption_lang = null;
  10570. $caption_startTime = null;
  10571. $caption_endTime = null;
  10572. $caption_text = null;
  10573. if (isset($caption['attribs']['']['type']))
  10574. {
  10575. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10576. }
  10577. if (isset($caption['attribs']['']['lang']))
  10578. {
  10579. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  10580. }
  10581. if (isset($caption['attribs']['']['start']))
  10582. {
  10583. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  10584. }
  10585. if (isset($caption['attribs']['']['end']))
  10586. {
  10587. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  10588. }
  10589. if (isset($caption['data']))
  10590. {
  10591. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10592. }
  10593. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  10594. }
  10595. if (is_array($captions))
  10596. {
  10597. $captions = array_values(array_unique($captions));
  10598. }
  10599. }
  10600. else
  10601. {
  10602. $captions = $captions_parent;
  10603. }
  10604. // CATEGORIES
  10605. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  10606. {
  10607. foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  10608. {
  10609. $term = null;
  10610. $scheme = null;
  10611. $label = null;
  10612. if (isset($category['data']))
  10613. {
  10614. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10615. }
  10616. if (isset($category['attribs']['']['scheme']))
  10617. {
  10618. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10619. }
  10620. else
  10621. {
  10622. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  10623. }
  10624. if (isset($category['attribs']['']['label']))
  10625. {
  10626. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  10627. }
  10628. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  10629. }
  10630. }
  10631. if (is_array($categories) && is_array($categories_parent))
  10632. {
  10633. $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
  10634. }
  10635. elseif (is_array($categories))
  10636. {
  10637. $categories = array_values(array_unique($categories));
  10638. }
  10639. elseif (is_array($categories_parent))
  10640. {
  10641. $categories = array_values(array_unique($categories_parent));
  10642. }
  10643. else
  10644. {
  10645. $categories = null;
  10646. }
  10647. // COPYRIGHTS
  10648. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  10649. {
  10650. $copyright_url = null;
  10651. $copyright_label = null;
  10652. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  10653. {
  10654. $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  10655. }
  10656. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  10657. {
  10658. $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10659. }
  10660. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  10661. }
  10662. else
  10663. {
  10664. $copyrights = $copyrights_parent;
  10665. }
  10666. // CREDITS
  10667. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  10668. {
  10669. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  10670. {
  10671. $credit_role = null;
  10672. $credit_scheme = null;
  10673. $credit_name = null;
  10674. if (isset($credit['attribs']['']['role']))
  10675. {
  10676. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  10677. }
  10678. if (isset($credit['attribs']['']['scheme']))
  10679. {
  10680. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10681. }
  10682. else
  10683. {
  10684. $credit_scheme = 'urn:ebu';
  10685. }
  10686. if (isset($credit['data']))
  10687. {
  10688. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10689. }
  10690. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  10691. }
  10692. if (is_array($credits))
  10693. {
  10694. $credits = array_values(array_unique($credits));
  10695. }
  10696. }
  10697. else
  10698. {
  10699. $credits = $credits_parent;
  10700. }
  10701. // DESCRIPTION
  10702. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  10703. {
  10704. $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10705. }
  10706. else
  10707. {
  10708. $description = $description_parent;
  10709. }
  10710. // HASHES
  10711. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  10712. {
  10713. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  10714. {
  10715. $value = null;
  10716. $algo = null;
  10717. if (isset($hash['data']))
  10718. {
  10719. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10720. }
  10721. if (isset($hash['attribs']['']['algo']))
  10722. {
  10723. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  10724. }
  10725. else
  10726. {
  10727. $algo = 'md5';
  10728. }
  10729. $hashes[] = $algo.':'.$value;
  10730. }
  10731. if (is_array($hashes))
  10732. {
  10733. $hashes = array_values(array_unique($hashes));
  10734. }
  10735. }
  10736. else
  10737. {
  10738. $hashes = $hashes_parent;
  10739. }
  10740. // KEYWORDS
  10741. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  10742. {
  10743. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  10744. {
  10745. $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10746. foreach ($temp as $word)
  10747. {
  10748. $keywords[] = trim($word);
  10749. }
  10750. unset($temp);
  10751. }
  10752. if (is_array($keywords))
  10753. {
  10754. $keywords = array_values(array_unique($keywords));
  10755. }
  10756. }
  10757. else
  10758. {
  10759. $keywords = $keywords_parent;
  10760. }
  10761. // PLAYER
  10762. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  10763. {
  10764. $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10765. }
  10766. else
  10767. {
  10768. $player = $player_parent;
  10769. }
  10770. // RATINGS
  10771. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  10772. {
  10773. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  10774. {
  10775. $rating_scheme = null;
  10776. $rating_value = null;
  10777. if (isset($rating['attribs']['']['scheme']))
  10778. {
  10779. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10780. }
  10781. else
  10782. {
  10783. $rating_scheme = 'urn:simple';
  10784. }
  10785. if (isset($rating['data']))
  10786. {
  10787. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10788. }
  10789. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10790. }
  10791. if (is_array($ratings))
  10792. {
  10793. $ratings = array_values(array_unique($ratings));
  10794. }
  10795. }
  10796. else
  10797. {
  10798. $ratings = $ratings_parent;
  10799. }
  10800. // RESTRICTIONS
  10801. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  10802. {
  10803. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  10804. {
  10805. $restriction_relationship = null;
  10806. $restriction_type = null;
  10807. $restriction_value = null;
  10808. if (isset($restriction['attribs']['']['relationship']))
  10809. {
  10810. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  10811. }
  10812. if (isset($restriction['attribs']['']['type']))
  10813. {
  10814. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10815. }
  10816. if (isset($restriction['data']))
  10817. {
  10818. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10819. }
  10820. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10821. }
  10822. if (is_array($restrictions))
  10823. {
  10824. $restrictions = array_values(array_unique($restrictions));
  10825. }
  10826. }
  10827. else
  10828. {
  10829. $restrictions = $restrictions_parent;
  10830. }
  10831. // THUMBNAILS
  10832. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  10833. {
  10834. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  10835. {
  10836. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10837. }
  10838. if (is_array($thumbnails))
  10839. {
  10840. $thumbnails = array_values(array_unique($thumbnails));
  10841. }
  10842. }
  10843. else
  10844. {
  10845. $thumbnails = $thumbnails_parent;
  10846. }
  10847. // TITLES
  10848. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  10849. {
  10850. $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10851. }
  10852. else
  10853. {
  10854. $title = $title_parent;
  10855. }
  10856. $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));
  10857. }
  10858. }
  10859. }
  10860. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  10861. {
  10862. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  10863. {
  10864. // Attributes
  10865. $bitrate = null;
  10866. $channels = null;
  10867. $duration = null;
  10868. $expression = null;
  10869. $framerate = null;
  10870. $height = null;
  10871. $javascript = null;
  10872. $lang = null;
  10873. $length = null;
  10874. $medium = null;
  10875. $samplingrate = null;
  10876. $type = null;
  10877. $url = null;
  10878. $width = null;
  10879. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  10880. if (isset($link['attribs']['']['type']))
  10881. {
  10882. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10883. }
  10884. if (isset($link['attribs']['']['length']))
  10885. {
  10886. $length = ceil($link['attribs']['']['length']);
  10887. }
  10888. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  10889. $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));
  10890. }
  10891. }
  10892. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  10893. {
  10894. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  10895. {
  10896. // Attributes
  10897. $bitrate = null;
  10898. $channels = null;
  10899. $duration = null;
  10900. $expression = null;
  10901. $framerate = null;
  10902. $height = null;
  10903. $javascript = null;
  10904. $lang = null;
  10905. $length = null;
  10906. $medium = null;
  10907. $samplingrate = null;
  10908. $type = null;
  10909. $url = null;
  10910. $width = null;
  10911. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  10912. if (isset($link['attribs']['']['type']))
  10913. {
  10914. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10915. }
  10916. if (isset($link['attribs']['']['length']))
  10917. {
  10918. $length = ceil($link['attribs']['']['length']);
  10919. }
  10920. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  10921. $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));
  10922. }
  10923. }
  10924. if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
  10925. {
  10926. if (isset($enclosure[0]['attribs']['']['url']))
  10927. {
  10928. // Attributes
  10929. $bitrate = null;
  10930. $channels = null;
  10931. $duration = null;
  10932. $expression = null;
  10933. $framerate = null;
  10934. $height = null;
  10935. $javascript = null;
  10936. $lang = null;
  10937. $length = null;
  10938. $medium = null;
  10939. $samplingrate = null;
  10940. $type = null;
  10941. $url = null;
  10942. $width = null;
  10943. $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
  10944. if (isset($enclosure[0]['attribs']['']['type']))
  10945. {
  10946. $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10947. }
  10948. if (isset($enclosure[0]['attribs']['']['length']))
  10949. {
  10950. $length = ceil($enclosure[0]['attribs']['']['length']);
  10951. }
  10952. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  10953. $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));
  10954. }
  10955. }
  10956. 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))
  10957. {
  10958. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  10959. $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));
  10960. }
  10961. $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
  10962. }
  10963. if (!empty($this->data['enclosures']))
  10964. {
  10965. return $this->data['enclosures'];
  10966. }
  10967. else
  10968. {
  10969. return null;
  10970. }
  10971. }
  10972. /**
  10973. * Get the latitude coordinates for the item
  10974. *
  10975. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  10976. *
  10977. * Uses `<geo:lat>` or `<georss:point>`
  10978. *
  10979. * @since 1.0
  10980. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  10981. * @link http://www.georss.org/ GeoRSS
  10982. * @return string|null
  10983. */
  10984. public function get_latitude()
  10985. {
  10986. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  10987. {
  10988. return (float) $return[0]['data'];
  10989. }
  10990. 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))
  10991. {
  10992. return (float) $match[1];
  10993. }
  10994. else
  10995. {
  10996. return null;
  10997. }
  10998. }
  10999. /**
  11000. * Get the longitude coordinates for the item
  11001. *
  11002. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  11003. *
  11004. * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
  11005. *
  11006. * @since 1.0
  11007. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  11008. * @link http://www.georss.org/ GeoRSS
  11009. * @return string|null
  11010. */
  11011. public function get_longitude()
  11012. {
  11013. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  11014. {
  11015. return (float) $return[0]['data'];
  11016. }
  11017. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  11018. {
  11019. return (float) $return[0]['data'];
  11020. }
  11021. 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))
  11022. {
  11023. return (float) $match[2];
  11024. }
  11025. else
  11026. {
  11027. return null;
  11028. }
  11029. }
  11030. /**
  11031. * Get the `<atom:source>` for the item
  11032. *
  11033. * @since 1.1
  11034. * @return SimplePie_Source|null
  11035. */
  11036. public function get_source()
  11037. {
  11038. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
  11039. {
  11040. return $this->registry->create('Source', array($this, $return[0]));
  11041. }
  11042. else
  11043. {
  11044. return null;
  11045. }
  11046. }
  11047. }
  11048. /**
  11049. * Used for feed auto-discovery
  11050. *
  11051. *
  11052. * This class can be overloaded with {@see SimplePie::set_locator_class()}
  11053. *
  11054. * @package SimplePie
  11055. */
  11056. class SimplePie_Locator
  11057. {
  11058. var $useragent;
  11059. var $timeout;
  11060. var $file;
  11061. var $local = array();
  11062. var $elsewhere = array();
  11063. var $cached_entities = array();
  11064. var $http_base;
  11065. var $base;
  11066. var $base_location = 0;
  11067. var $checked_feeds = 0;
  11068. var $max_checked_feeds = 10;
  11069. protected $registry;
  11070. public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
  11071. {
  11072. $this->file = $file;
  11073. $this->useragent = $useragent;
  11074. $this->timeout = $timeout;
  11075. $this->max_checked_feeds = $max_checked_feeds;
  11076. $this->dom = new DOMDocument();
  11077. set_error_handler(array('SimplePie_Misc', 'silence_errors'));
  11078. $this->dom->loadHTML($this->file->body);
  11079. restore_error_handler();
  11080. }
  11081. public function set_registry(SimplePie_Registry $registry)
  11082. {
  11083. $this->registry = $registry;
  11084. }
  11085. public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
  11086. {
  11087. if ($this->is_feed($this->file))
  11088. {
  11089. return $this->file;
  11090. }
  11091. if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
  11092. {
  11093. $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
  11094. if ($sniffer->get_type() !== 'text/html')
  11095. {
  11096. return null;
  11097. }
  11098. }
  11099. if ($type & ~SIMPLEPIE_LOCATOR_NONE)
  11100. {
  11101. $this->get_base();
  11102. }
  11103. if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
  11104. {
  11105. return $working[0];
  11106. }
  11107. if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
  11108. {
  11109. if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
  11110. {
  11111. return $working;
  11112. }
  11113. if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
  11114. {
  11115. return $working;
  11116. }
  11117. if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
  11118. {
  11119. return $working;
  11120. }
  11121. if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
  11122. {
  11123. return $working;
  11124. }
  11125. }
  11126. return null;
  11127. }
  11128. public function is_feed($file)
  11129. {
  11130. if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
  11131. {
  11132. $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
  11133. $sniffed = $sniffer->get_type();
  11134. if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
  11135. {
  11136. return true;
  11137. }
  11138. else
  11139. {
  11140. return false;
  11141. }
  11142. }
  11143. elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
  11144. {
  11145. return true;
  11146. }
  11147. else
  11148. {
  11149. return false;
  11150. }
  11151. }
  11152. public function get_base()
  11153. {
  11154. $this->http_base = $this->file->url;
  11155. $this->base = $this->http_base;
  11156. $elements = $this->dom->getElementsByTagName('base');
  11157. foreach ($elements as $element)
  11158. {
  11159. if ($element->hasAttribute('href'))
  11160. {
  11161. $this->base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
  11162. $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
  11163. break;
  11164. }
  11165. }
  11166. }
  11167. public function autodiscovery()
  11168. {
  11169. $done = array();
  11170. $feeds = array();
  11171. $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
  11172. $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
  11173. $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
  11174. if (!empty($feeds))
  11175. {
  11176. return array_values($feeds);
  11177. }
  11178. else
  11179. {
  11180. return null;
  11181. }
  11182. }
  11183. protected function search_elements_by_tag($name, &$done, $feeds)
  11184. {
  11185. $links = $this->dom->getElementsByTagName($name);
  11186. foreach ($links as $link)
  11187. {
  11188. if ($this->checked_feeds === $this->max_checked_feeds)
  11189. {
  11190. break;
  11191. }
  11192. if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
  11193. {
  11194. $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
  11195. $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
  11196. if ($this->base_location < $line)
  11197. {
  11198. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
  11199. }
  11200. else
  11201. {
  11202. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
  11203. }
  11204. 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]))
  11205. {
  11206. $this->checked_feeds++;
  11207. $headers = array(
  11208. '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',
  11209. );
  11210. $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
  11211. 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))
  11212. {
  11213. $feeds[$href] = $feed;
  11214. }
  11215. }
  11216. $done[] = $href;
  11217. }
  11218. }
  11219. return $feeds;
  11220. }
  11221. public function get_links()
  11222. {
  11223. $links = $this->dom->getElementsByTagName('a');
  11224. foreach ($links as $link)
  11225. {
  11226. if ($link->hasAttribute('href'))
  11227. {
  11228. $href = trim($link->getAttribute('href'));
  11229. $parsed = $this->registry->call('Misc', 'parse_url', array($href));
  11230. if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
  11231. {
  11232. if ($this->base_location < $link->getLineNo())
  11233. {
  11234. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
  11235. }
  11236. else
  11237. {
  11238. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
  11239. }
  11240. $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
  11241. if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
  11242. {
  11243. $this->local[] = $href;
  11244. }
  11245. else
  11246. {
  11247. $this->elsewhere[] = $href;
  11248. }
  11249. }
  11250. }
  11251. }
  11252. $this->local = array_unique($this->local);
  11253. $this->elsewhere = array_unique($this->elsewhere);
  11254. if (!empty($this->local) || !empty($this->elsewhere))
  11255. {
  11256. return true;
  11257. }
  11258. return null;
  11259. }
  11260. public function extension(&$array)
  11261. {
  11262. foreach ($array as $key => $value)
  11263. {
  11264. if ($this->checked_feeds === $this->max_checked_feeds)
  11265. {
  11266. break;
  11267. }
  11268. if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
  11269. {
  11270. $this->checked_feeds++;
  11271. $headers = array(
  11272. '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',
  11273. );
  11274. $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
  11275. 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))
  11276. {
  11277. return $feed;
  11278. }
  11279. else
  11280. {
  11281. unset($array[$key]);
  11282. }
  11283. }
  11284. }
  11285. return null;
  11286. }
  11287. public function body(&$array)
  11288. {
  11289. foreach ($array as $key => $value)
  11290. {
  11291. if ($this->checked_feeds === $this->max_checked_feeds)
  11292. {
  11293. break;
  11294. }
  11295. if (preg_match('/(rss|rdf|atom|xml)/i', $value))
  11296. {
  11297. $this->checked_feeds++;
  11298. $headers = array(
  11299. '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',
  11300. );
  11301. $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
  11302. 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))
  11303. {
  11304. return $feed;
  11305. }
  11306. else
  11307. {
  11308. unset($array[$key]);
  11309. }
  11310. }
  11311. }
  11312. return null;
  11313. }
  11314. }
  11315. /**
  11316. * Miscellanous utilities
  11317. *
  11318. * @package SimplePie
  11319. */
  11320. class SimplePie_Misc
  11321. {
  11322. public static function time_hms($seconds)
  11323. {
  11324. $time = '';
  11325. $hours = floor($seconds / 3600);
  11326. $remainder = $seconds % 3600;
  11327. if ($hours > 0)
  11328. {
  11329. $time .= $hours.':';
  11330. }
  11331. $minutes = floor($remainder / 60);
  11332. $seconds = $remainder % 60;
  11333. if ($minutes < 10 && $hours > 0)
  11334. {
  11335. $minutes = '0' . $minutes;
  11336. }
  11337. if ($seconds < 10)
  11338. {
  11339. $seconds = '0' . $seconds;
  11340. }
  11341. $time .= $minutes.':';
  11342. $time .= $seconds;
  11343. return $time;
  11344. }
  11345. public static function absolutize_url($relative, $base)
  11346. {
  11347. $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
  11348. return $iri->get_uri();
  11349. }
  11350. /**
  11351. * Get a HTML/XML element from a HTML string
  11352. *
  11353. * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
  11354. * @param string $realname Element name (including namespace prefix if applicable)
  11355. * @param string $string HTML document
  11356. * @return array
  11357. */
  11358. public static function get_element($realname, $string)
  11359. {
  11360. $return = array();
  11361. $name = preg_quote($realname, '/');
  11362. if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
  11363. {
  11364. for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
  11365. {
  11366. $return[$i]['tag'] = $realname;
  11367. $return[$i]['full'] = $matches[$i][0][0];
  11368. $return[$i]['offset'] = $matches[$i][0][1];
  11369. if (strlen($matches[$i][3][0]) <= 2)
  11370. {
  11371. $return[$i]['self_closing'] = true;
  11372. }
  11373. else
  11374. {
  11375. $return[$i]['self_closing'] = false;
  11376. $return[$i]['content'] = $matches[$i][4][0];
  11377. }
  11378. $return[$i]['attribs'] = array();
  11379. 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))
  11380. {
  11381. for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
  11382. {
  11383. if (count($attribs[$j]) === 2)
  11384. {
  11385. $attribs[$j][2] = $attribs[$j][1];
  11386. }
  11387. $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
  11388. }
  11389. }
  11390. }
  11391. }
  11392. return $return;
  11393. }
  11394. public static function element_implode($element)
  11395. {
  11396. $full = "<$element[tag]";
  11397. foreach ($element['attribs'] as $key => $value)
  11398. {
  11399. $key = strtolower($key);
  11400. $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
  11401. }
  11402. if ($element['self_closing'])
  11403. {
  11404. $full .= ' />';
  11405. }
  11406. else
  11407. {
  11408. $full .= ">$element[content]</$element[tag]>";
  11409. }
  11410. return $full;
  11411. }
  11412. public static function error($message, $level, $file, $line)
  11413. {
  11414. if ((ini_get('error_reporting') & $level) > 0)
  11415. {
  11416. switch ($level)
  11417. {
  11418. case E_USER_ERROR:
  11419. $note = 'PHP Error';
  11420. break;
  11421. case E_USER_WARNING:
  11422. $note = 'PHP Warning';
  11423. break;
  11424. case E_USER_NOTICE:
  11425. $note = 'PHP Notice';
  11426. break;
  11427. default:
  11428. $note = 'Unknown Error';
  11429. break;
  11430. }
  11431. $log_error = true;
  11432. if (!function_exists('error_log'))
  11433. {
  11434. $log_error = false;
  11435. }
  11436. $log_file = @ini_get('error_log');
  11437. if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
  11438. {
  11439. $log_error = false;
  11440. }
  11441. if ($log_error)
  11442. {
  11443. @error_log("$note: $message in $file on line $line", 0);
  11444. }
  11445. }
  11446. return $message;
  11447. }
  11448. public static function fix_protocol($url, $http = 1)
  11449. {
  11450. $url = SimplePie_Misc::normalize_url($url);
  11451. $parsed = SimplePie_Misc::parse_url($url);
  11452. if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
  11453. {
  11454. return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
  11455. }
  11456. if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
  11457. {
  11458. return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
  11459. }
  11460. if ($http === 2 && $parsed['scheme'] !== '')
  11461. {
  11462. return "feed:$url";
  11463. }
  11464. elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
  11465. {
  11466. return substr_replace($url, 'podcast', 0, 4);
  11467. }
  11468. elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
  11469. {
  11470. return substr_replace($url, 'itpc', 0, 4);
  11471. }
  11472. else
  11473. {
  11474. return $url;
  11475. }
  11476. }
  11477. public static function parse_url($url)
  11478. {
  11479. $iri = new SimplePie_IRI($url);
  11480. return array(
  11481. 'scheme' => (string) $iri->scheme,
  11482. 'authority' => (string) $iri->authority,
  11483. 'path' => (string) $iri->path,
  11484. 'query' => (string) $iri->query,
  11485. 'fragment' => (string) $iri->fragment
  11486. );
  11487. }
  11488. public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
  11489. {
  11490. $iri = new SimplePie_IRI('');
  11491. $iri->scheme = $scheme;
  11492. $iri->authority = $authority;
  11493. $iri->path = $path;
  11494. $iri->query = $query;
  11495. $iri->fragment = $fragment;
  11496. return $iri->get_uri();
  11497. }
  11498. public static function normalize_url($url)
  11499. {
  11500. $iri = new SimplePie_IRI($url);
  11501. return $iri->get_uri();
  11502. }
  11503. public static function percent_encoding_normalization($match)
  11504. {
  11505. $integer = hexdec($match[1]);
  11506. if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
  11507. {
  11508. return chr($integer);
  11509. }
  11510. else
  11511. {
  11512. return strtoupper($match[0]);
  11513. }
  11514. }
  11515. /**
  11516. * Converts a Windows-1252 encoded string to a UTF-8 encoded string
  11517. *
  11518. * @static
  11519. * @param string $string Windows-1252 encoded string
  11520. * @return string UTF-8 encoded string
  11521. */
  11522. public static function windows_1252_to_utf8($string)
  11523. {
  11524. 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");
  11525. return strtr($string, $convert_table);
  11526. }
  11527. /**
  11528. * Change a string from one encoding to another
  11529. *
  11530. * @param string $data Raw data in $input encoding
  11531. * @param string $input Encoding of $data
  11532. * @param string $output Encoding you want
  11533. * @return string|boolean False if we can't convert it
  11534. */
  11535. public static function change_encoding($data, $input, $output)
  11536. {
  11537. $input = SimplePie_Misc::encoding($input);
  11538. $output = SimplePie_Misc::encoding($output);
  11539. // We fail to fail on non US-ASCII bytes
  11540. if ($input === 'US-ASCII')
  11541. {
  11542. static $non_ascii_octects = '';
  11543. if (!$non_ascii_octects)
  11544. {
  11545. for ($i = 0x80; $i <= 0xFF; $i++)
  11546. {
  11547. $non_ascii_octects .= chr($i);
  11548. }
  11549. }
  11550. $data = substr($data, 0, strcspn($data, $non_ascii_octects));
  11551. }
  11552. // This is first, as behaviour of this is completely predictable
  11553. if ($input === 'windows-1252' && $output === 'UTF-8')
  11554. {
  11555. return SimplePie_Misc::windows_1252_to_utf8($data);
  11556. }
  11557. // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
  11558. elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
  11559. {
  11560. return $return;
  11561. }
  11562. // This is last, as behaviour of this varies with OS userland and PHP version
  11563. elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
  11564. {
  11565. return $return;
  11566. }
  11567. // If we can't do anything, just fail
  11568. else
  11569. {
  11570. return false;
  11571. }
  11572. }
  11573. protected static function change_encoding_mbstring($data, $input, $output)
  11574. {
  11575. if ($input === 'windows-949')
  11576. {
  11577. $input = 'EUC-KR';
  11578. }
  11579. if ($output === 'windows-949')
  11580. {
  11581. $output = 'EUC-KR';
  11582. }
  11583. if ($input === 'Windows-31J')
  11584. {
  11585. $input = 'SJIS';
  11586. }
  11587. if ($output === 'Windows-31J')
  11588. {
  11589. $output = 'SJIS';
  11590. }
  11591. // Check that the encoding is supported
  11592. if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
  11593. {
  11594. return false;
  11595. }
  11596. if (!in_array($input, mb_list_encodings()))
  11597. {
  11598. return false;
  11599. }
  11600. // Let's do some conversion
  11601. if ($return = @mb_convert_encoding($data, $output, $input))
  11602. {
  11603. return $return;
  11604. }
  11605. return false;
  11606. }
  11607. protected static function change_encoding_iconv($data, $input, $output)
  11608. {
  11609. return @iconv($input, $output, $data);
  11610. }
  11611. /**
  11612. * Normalize an encoding name
  11613. *
  11614. * This is automatically generated by create.php
  11615. *
  11616. * To generate it, run `php create.php` on the command line, and copy the
  11617. * output to replace this function.
  11618. *
  11619. * @param string $charset Character set to standardise
  11620. * @return string Standardised name
  11621. */
  11622. public static function encoding($charset)
  11623. {
  11624. // Normalization from UTS #22
  11625. switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
  11626. {
  11627. case 'adobestandardencoding':
  11628. case 'csadobestandardencoding':
  11629. return 'Adobe-Standard-Encoding';
  11630. case 'adobesymbolencoding':
  11631. case 'cshppsmath':
  11632. return 'Adobe-Symbol-Encoding';
  11633. case 'ami1251':
  11634. case 'amiga1251':
  11635. return 'Amiga-1251';
  11636. case 'ansix31101983':
  11637. case 'csat5001983':
  11638. case 'csiso99naplps':
  11639. case 'isoir99':
  11640. case 'naplps':
  11641. return 'ANSI_X3.110-1983';
  11642. case 'arabic7':
  11643. case 'asmo449':
  11644. case 'csiso89asmo449':
  11645. case 'iso9036':
  11646. case 'isoir89':
  11647. return 'ASMO_449';
  11648. case 'big5':
  11649. case 'csbig5':
  11650. return 'Big5';
  11651. case 'big5hkscs':
  11652. return 'Big5-HKSCS';
  11653. case 'bocu1':
  11654. case 'csbocu1':
  11655. return 'BOCU-1';
  11656. case 'brf':
  11657. case 'csbrf':
  11658. return 'BRF';
  11659. case 'bs4730':
  11660. case 'csiso4unitedkingdom':
  11661. case 'gb':
  11662. case 'iso646gb':
  11663. case 'isoir4':
  11664. case 'uk':
  11665. return 'BS_4730';
  11666. case 'bsviewdata':
  11667. case 'csiso47bsviewdata':
  11668. case 'isoir47':
  11669. return 'BS_viewdata';
  11670. case 'cesu8':
  11671. case 'cscesu8':
  11672. return 'CESU-8';
  11673. case 'ca':
  11674. case 'csa71':
  11675. case 'csaz243419851':
  11676. case 'csiso121canadian1':
  11677. case 'iso646ca':
  11678. case 'isoir121':
  11679. return 'CSA_Z243.4-1985-1';
  11680. case 'csa72':
  11681. case 'csaz243419852':
  11682. case 'csiso122canadian2':
  11683. case 'iso646ca2':
  11684. case 'isoir122':
  11685. return 'CSA_Z243.4-1985-2';
  11686. case 'csaz24341985gr':
  11687. case 'csiso123csaz24341985gr':
  11688. case 'isoir123':
  11689. return 'CSA_Z243.4-1985-gr';
  11690. case 'csiso139csn369103':
  11691. case 'csn369103':
  11692. case 'isoir139':
  11693. return 'CSN_369103';
  11694. case 'csdecmcs':
  11695. case 'dec':
  11696. case 'decmcs':
  11697. return 'DEC-MCS';
  11698. case 'csiso21german':
  11699. case 'de':
  11700. case 'din66003':
  11701. case 'iso646de':
  11702. case 'isoir21':
  11703. return 'DIN_66003';
  11704. case 'csdkus':
  11705. case 'dkus':
  11706. return 'dk-us';
  11707. case 'csiso646danish':
  11708. case 'dk':
  11709. case 'ds2089':
  11710. case 'iso646dk':
  11711. return 'DS_2089';
  11712. case 'csibmebcdicatde':
  11713. case 'ebcdicatde':
  11714. return 'EBCDIC-AT-DE';
  11715. case 'csebcdicatdea':
  11716. case 'ebcdicatdea':
  11717. return 'EBCDIC-AT-DE-A';
  11718. case 'csebcdiccafr':
  11719. case 'ebcdiccafr':
  11720. return 'EBCDIC-CA-FR';
  11721. case 'csebcdicdkno':
  11722. case 'ebcdicdkno':
  11723. return 'EBCDIC-DK-NO';
  11724. case 'csebcdicdknoa':
  11725. case 'ebcdicdknoa':
  11726. return 'EBCDIC-DK-NO-A';
  11727. case 'csebcdices':
  11728. case 'ebcdices':
  11729. return 'EBCDIC-ES';
  11730. case 'csebcdicesa':
  11731. case 'ebcdicesa':
  11732. return 'EBCDIC-ES-A';
  11733. case 'csebcdicess':
  11734. case 'ebcdicess':
  11735. return 'EBCDIC-ES-S';
  11736. case 'csebcdicfise':
  11737. case 'ebcdicfise':
  11738. return 'EBCDIC-FI-SE';
  11739. case 'csebcdicfisea':
  11740. case 'ebcdicfisea':
  11741. return 'EBCDIC-FI-SE-A';
  11742. case 'csebcdicfr':
  11743. case 'ebcdicfr':
  11744. return 'EBCDIC-FR';
  11745. case 'csebcdicit':
  11746. case 'ebcdicit':
  11747. return 'EBCDIC-IT';
  11748. case 'csebcdicpt':
  11749. case 'ebcdicpt':
  11750. return 'EBCDIC-PT';
  11751. case 'csebcdicuk':
  11752. case 'ebcdicuk':
  11753. return 'EBCDIC-UK';
  11754. case 'csebcdicus':
  11755. case 'ebcdicus':
  11756. return 'EBCDIC-US';
  11757. case 'csiso111ecmacyrillic':
  11758. case 'ecmacyrillic':
  11759. case 'isoir111':
  11760. case 'koi8e':
  11761. return 'ECMA-cyrillic';
  11762. case 'csiso17spanish':
  11763. case 'es':
  11764. case 'iso646es':
  11765. case 'isoir17':
  11766. return 'ES';
  11767. case 'csiso85spanish2':
  11768. case 'es2':
  11769. case 'iso646es2':
  11770. case 'isoir85':
  11771. return 'ES2';
  11772. case 'cseucpkdfmtjapanese':
  11773. case 'eucjp':
  11774. case 'extendedunixcodepackedformatforjapanese':
  11775. return 'EUC-JP';
  11776. case 'cseucfixwidjapanese':
  11777. case 'extendedunixcodefixedwidthforjapanese':
  11778. return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
  11779. case 'gb18030':
  11780. return 'GB18030';
  11781. case 'chinese':
  11782. case 'cp936':
  11783. case 'csgb2312':
  11784. case 'csiso58gb231280':
  11785. case 'gb2312':
  11786. case 'gb231280':
  11787. case 'gbk':
  11788. case 'isoir58':
  11789. case 'ms936':
  11790. case 'windows936':
  11791. return 'GBK';
  11792. case 'cn':
  11793. case 'csiso57gb1988':
  11794. case 'gb198880':
  11795. case 'iso646cn':
  11796. case 'isoir57':
  11797. return 'GB_1988-80';
  11798. case 'csiso153gost1976874':
  11799. case 'gost1976874':
  11800. case 'isoir153':
  11801. case 'stsev35888':
  11802. return 'GOST_19768-74';
  11803. case 'csiso150':
  11804. case 'csiso150greekccitt':
  11805. case 'greekccitt':
  11806. case 'isoir150':
  11807. return 'greek-ccitt';
  11808. case 'csiso88greek7':
  11809. case 'greek7':
  11810. case 'isoir88':
  11811. return 'greek7';
  11812. case 'csiso18greek7old':
  11813. case 'greek7old':
  11814. case 'isoir18':
  11815. return 'greek7-old';
  11816. case 'cshpdesktop':
  11817. case 'hpdesktop':
  11818. return 'HP-DeskTop';
  11819. case 'cshplegal':
  11820. case 'hplegal':
  11821. return 'HP-Legal';
  11822. case 'cshpmath8':
  11823. case 'hpmath8':
  11824. return 'HP-Math8';
  11825. case 'cshppifont':
  11826. case 'hppifont':
  11827. return 'HP-Pi-font';
  11828. case 'cshproman8':
  11829. case 'hproman8':
  11830. case 'r8':
  11831. case 'roman8':
  11832. return 'hp-roman8';
  11833. case 'hzgb2312':
  11834. return 'HZ-GB-2312';
  11835. case 'csibmsymbols':
  11836. case 'ibmsymbols':
  11837. return 'IBM-Symbols';
  11838. case 'csibmthai':
  11839. case 'ibmthai':
  11840. return 'IBM-Thai';
  11841. case 'cp37':
  11842. case 'csibm37':
  11843. case 'ebcdiccpca':
  11844. case 'ebcdiccpnl':
  11845. case 'ebcdiccpus':
  11846. case 'ebcdiccpwt':
  11847. case 'ibm37':
  11848. return 'IBM037';
  11849. case 'cp38':
  11850. case 'csibm38':
  11851. case 'ebcdicint':
  11852. case 'ibm38':
  11853. return 'IBM038';
  11854. case 'cp273':
  11855. case 'csibm273':
  11856. case 'ibm273':
  11857. return 'IBM273';
  11858. case 'cp274':
  11859. case 'csibm274':
  11860. case 'ebcdicbe':
  11861. case 'ibm274':
  11862. return 'IBM274';
  11863. case 'cp275':
  11864. case 'csibm275':
  11865. case 'ebcdicbr':
  11866. case 'ibm275':
  11867. return 'IBM275';
  11868. case 'csibm277':
  11869. case 'ebcdiccpdk':
  11870. case 'ebcdiccpno':
  11871. case 'ibm277':
  11872. return 'IBM277';
  11873. case 'cp278':
  11874. case 'csibm278':
  11875. case 'ebcdiccpfi':
  11876. case 'ebcdiccpse':
  11877. case 'ibm278':
  11878. return 'IBM278';
  11879. case 'cp280':
  11880. case 'csibm280':
  11881. case 'ebcdiccpit':
  11882. case 'ibm280':
  11883. return 'IBM280';
  11884. case 'cp281':
  11885. case 'csibm281':
  11886. case 'ebcdicjpe':
  11887. case 'ibm281':
  11888. return 'IBM281';
  11889. case 'cp284':
  11890. case 'csibm284':
  11891. case 'ebcdiccpes':
  11892. case 'ibm284':
  11893. return 'IBM284';
  11894. case 'cp285':
  11895. case 'csibm285':
  11896. case 'ebcdiccpgb':
  11897. case 'ibm285':
  11898. return 'IBM285';
  11899. case 'cp290':
  11900. case 'csibm290':
  11901. case 'ebcdicjpkana':
  11902. case 'ibm290':
  11903. return 'IBM290';
  11904. case 'cp297':
  11905. case 'csibm297':
  11906. case 'ebcdiccpfr':
  11907. case 'ibm297':
  11908. return 'IBM297';
  11909. case 'cp420':
  11910. case 'csibm420':
  11911. case 'ebcdiccpar1':
  11912. case 'ibm420':
  11913. return 'IBM420';
  11914. case 'cp423':
  11915. case 'csibm423':
  11916. case 'ebcdiccpgr':
  11917. case 'ibm423':
  11918. return 'IBM423';
  11919. case 'cp424':
  11920. case 'csibm424':
  11921. case 'ebcdiccphe':
  11922. case 'ibm424':
  11923. return 'IBM424';
  11924. case '437':
  11925. case 'cp437':
  11926. case 'cspc8codepage437':
  11927. case 'ibm437':
  11928. return 'IBM437';
  11929. case 'cp500':
  11930. case 'csibm500':
  11931. case 'ebcdiccpbe':
  11932. case 'ebcdiccpch':
  11933. case 'ibm500':
  11934. return 'IBM500';
  11935. case 'cp775':
  11936. case 'cspc775baltic':
  11937. case 'ibm775':
  11938. return 'IBM775';
  11939. case '850':
  11940. case 'cp850':
  11941. case 'cspc850multilingual':
  11942. case 'ibm850':
  11943. return 'IBM850';
  11944. case '851':
  11945. case 'cp851':
  11946. case 'csibm851':
  11947. case 'ibm851':
  11948. return 'IBM851';
  11949. case '852':
  11950. case 'cp852':
  11951. case 'cspcp852':
  11952. case 'ibm852':
  11953. return 'IBM852';
  11954. case '855':
  11955. case 'cp855':
  11956. case 'csibm855':
  11957. case 'ibm855':
  11958. return 'IBM855';
  11959. case '857':
  11960. case 'cp857':
  11961. case 'csibm857':
  11962. case 'ibm857':
  11963. return 'IBM857';
  11964. case 'ccsid858':
  11965. case 'cp858':
  11966. case 'ibm858':
  11967. case 'pcmultilingual850euro':
  11968. return 'IBM00858';
  11969. case '860':
  11970. case 'cp860':
  11971. case 'csibm860':
  11972. case 'ibm860':
  11973. return 'IBM860';
  11974. case '861':
  11975. case 'cp861':
  11976. case 'cpis':
  11977. case 'csibm861':
  11978. case 'ibm861':
  11979. return 'IBM861';
  11980. case '862':
  11981. case 'cp862':
  11982. case 'cspc862latinhebrew':
  11983. case 'ibm862':
  11984. return 'IBM862';
  11985. case '863':
  11986. case 'cp863':
  11987. case 'csibm863':
  11988. case 'ibm863':
  11989. return 'IBM863';
  11990. case 'cp864':
  11991. case 'csibm864':
  11992. case 'ibm864':
  11993. return 'IBM864';
  11994. case '865':
  11995. case 'cp865':
  11996. case 'csibm865':
  11997. case 'ibm865':
  11998. return 'IBM865';
  11999. case '866':
  12000. case 'cp866':
  12001. case 'csibm866':
  12002. case 'ibm866':
  12003. return 'IBM866';
  12004. case 'cp868':
  12005. case 'cpar':
  12006. case 'csibm868':
  12007. case 'ibm868':
  12008. return 'IBM868';
  12009. case '869':
  12010. case 'cp869':
  12011. case 'cpgr':
  12012. case 'csibm869':
  12013. case 'ibm869':
  12014. return 'IBM869';
  12015. case 'cp870':
  12016. case 'csibm870':
  12017. case 'ebcdiccproece':
  12018. case 'ebcdiccpyu':
  12019. case 'ibm870':
  12020. return 'IBM870';
  12021. case 'cp871':
  12022. case 'csibm871':
  12023. case 'ebcdiccpis':
  12024. case 'ibm871':
  12025. return 'IBM871';
  12026. case 'cp880':
  12027. case 'csibm880':
  12028. case 'ebcdiccyrillic':
  12029. case 'ibm880':
  12030. return 'IBM880';
  12031. case 'cp891':
  12032. case 'csibm891':
  12033. case 'ibm891':
  12034. return 'IBM891';
  12035. case 'cp903':
  12036. case 'csibm903':
  12037. case 'ibm903':
  12038. return 'IBM903';
  12039. case '904':
  12040. case 'cp904':
  12041. case 'csibbm904':
  12042. case 'ibm904':
  12043. return 'IBM904';
  12044. case 'cp905':
  12045. case 'csibm905':
  12046. case 'ebcdiccptr':
  12047. case 'ibm905':
  12048. return 'IBM905';
  12049. case 'cp918':
  12050. case 'csibm918':
  12051. case 'ebcdiccpar2':
  12052. case 'ibm918':
  12053. return 'IBM918';
  12054. case 'ccsid924':
  12055. case 'cp924':
  12056. case 'ebcdiclatin9euro':
  12057. case 'ibm924':
  12058. return 'IBM00924';
  12059. case 'cp1026':
  12060. case 'csibm1026':
  12061. case 'ibm1026':
  12062. return 'IBM1026';
  12063. case 'ibm1047':
  12064. return 'IBM1047';
  12065. case 'ccsid1140':
  12066. case 'cp1140':
  12067. case 'ebcdicus37euro':
  12068. case 'ibm1140':
  12069. return 'IBM01140';
  12070. case 'ccsid1141':
  12071. case 'cp1141':
  12072. case 'ebcdicde273euro':
  12073. case 'ibm1141':
  12074. return 'IBM01141';
  12075. case 'ccsid1142':
  12076. case 'cp1142':
  12077. case 'ebcdicdk277euro':
  12078. case 'ebcdicno277euro':
  12079. case 'ibm1142':
  12080. return 'IBM01142';
  12081. case 'ccsid1143':
  12082. case 'cp1143':
  12083. case 'ebcdicfi278euro':
  12084. case 'ebcdicse278euro':
  12085. case 'ibm1143':
  12086. return 'IBM01143';
  12087. case 'ccsid1144':
  12088. case 'cp1144':
  12089. case 'ebcdicit280euro':
  12090. case 'ibm1144':
  12091. return 'IBM01144';
  12092. case 'ccsid1145':
  12093. case 'cp1145':
  12094. case 'ebcdices284euro':
  12095. case 'ibm1145':
  12096. return 'IBM01145';
  12097. case 'ccsid1146':
  12098. case 'cp1146':
  12099. case 'ebcdicgb285euro':
  12100. case 'ibm1146':
  12101. return 'IBM01146';
  12102. case 'ccsid1147':
  12103. case 'cp1147':
  12104. case 'ebcdicfr297euro':
  12105. case 'ibm1147':
  12106. return 'IBM01147';
  12107. case 'ccsid1148':
  12108. case 'cp1148':
  12109. case 'ebcdicinternational500euro':
  12110. case 'ibm1148':
  12111. return 'IBM01148';
  12112. case 'ccsid1149':
  12113. case 'cp1149':
  12114. case 'ebcdicis871euro':
  12115. case 'ibm1149':
  12116. return 'IBM01149';
  12117. case 'csiso143iecp271':
  12118. case 'iecp271':
  12119. case 'isoir143':
  12120. return 'IEC_P27-1';
  12121. case 'csiso49inis':
  12122. case 'inis':
  12123. case 'isoir49':
  12124. return 'INIS';
  12125. case 'csiso50inis8':
  12126. case 'inis8':
  12127. case 'isoir50':
  12128. return 'INIS-8';
  12129. case 'csiso51iniscyrillic':
  12130. case 'iniscyrillic':
  12131. case 'isoir51':
  12132. return 'INIS-cyrillic';
  12133. case 'csinvariant':
  12134. case 'invariant':
  12135. return 'INVARIANT';
  12136. case 'iso2022cn':
  12137. return 'ISO-2022-CN';
  12138. case 'iso2022cnext':
  12139. return 'ISO-2022-CN-EXT';
  12140. case 'csiso2022jp':
  12141. case 'iso2022jp':
  12142. return 'ISO-2022-JP';
  12143. case 'csiso2022jp2':
  12144. case 'iso2022jp2':
  12145. return 'ISO-2022-JP-2';
  12146. case 'csiso2022kr':
  12147. case 'iso2022kr':
  12148. return 'ISO-2022-KR';
  12149. case 'cswindows30latin1':
  12150. case 'iso88591windows30latin1':
  12151. return 'ISO-8859-1-Windows-3.0-Latin-1';
  12152. case 'cswindows31latin1':
  12153. case 'iso88591windows31latin1':
  12154. return 'ISO-8859-1-Windows-3.1-Latin-1';
  12155. case 'csisolatin2':
  12156. case 'iso88592':
  12157. case 'iso885921987':
  12158. case 'isoir101':
  12159. case 'l2':
  12160. case 'latin2':
  12161. return 'ISO-8859-2';
  12162. case 'cswindows31latin2':
  12163. case 'iso88592windowslatin2':
  12164. return 'ISO-8859-2-Windows-Latin-2';
  12165. case 'csisolatin3':
  12166. case 'iso88593':
  12167. case 'iso885931988':
  12168. case 'isoir109':
  12169. case 'l3':
  12170. case 'latin3':
  12171. return 'ISO-8859-3';
  12172. case 'csisolatin4':
  12173. case 'iso88594':
  12174. case 'iso885941988':
  12175. case 'isoir110':
  12176. case 'l4':
  12177. case 'latin4':
  12178. return 'ISO-8859-4';
  12179. case 'csisolatincyrillic':
  12180. case 'cyrillic':
  12181. case 'iso88595':
  12182. case 'iso885951988':
  12183. case 'isoir144':
  12184. return 'ISO-8859-5';
  12185. case 'arabic':
  12186. case 'asmo708':
  12187. case 'csisolatinarabic':
  12188. case 'ecma114':
  12189. case 'iso88596':
  12190. case 'iso885961987':
  12191. case 'isoir127':
  12192. return 'ISO-8859-6';
  12193. case 'csiso88596e':
  12194. case 'iso88596e':
  12195. return 'ISO-8859-6-E';
  12196. case 'csiso88596i':
  12197. case 'iso88596i':
  12198. return 'ISO-8859-6-I';
  12199. case 'csisolatingreek':
  12200. case 'ecma118':
  12201. case 'elot928':
  12202. case 'greek':
  12203. case 'greek8':
  12204. case 'iso88597':
  12205. case 'iso885971987':
  12206. case 'isoir126':
  12207. return 'ISO-8859-7';
  12208. case 'csisolatinhebrew':
  12209. case 'hebrew':
  12210. case 'iso88598':
  12211. case 'iso885981988':
  12212. case 'isoir138':
  12213. return 'ISO-8859-8';
  12214. case 'csiso88598e':
  12215. case 'iso88598e':
  12216. return 'ISO-8859-8-E';
  12217. case 'csiso88598i':
  12218. case 'iso88598i':
  12219. return 'ISO-8859-8-I';
  12220. case 'cswindows31latin5':
  12221. case 'iso88599windowslatin5':
  12222. return 'ISO-8859-9-Windows-Latin-5';
  12223. case 'csisolatin6':
  12224. case 'iso885910':
  12225. case 'iso8859101992':
  12226. case 'isoir157':
  12227. case 'l6':
  12228. case 'latin6':
  12229. return 'ISO-8859-10';
  12230. case 'iso885913':
  12231. return 'ISO-8859-13';
  12232. case 'iso885914':
  12233. case 'iso8859141998':
  12234. case 'isoceltic':
  12235. case 'isoir199':
  12236. case 'l8':
  12237. case 'latin8':
  12238. return 'ISO-8859-14';
  12239. case 'iso885915':
  12240. case 'latin9':
  12241. return 'ISO-8859-15';
  12242. case 'iso885916':
  12243. case 'iso8859162001':
  12244. case 'isoir226':
  12245. case 'l10':
  12246. case 'latin10':
  12247. return 'ISO-8859-16';
  12248. case 'iso10646j1':
  12249. return 'ISO-10646-J-1';
  12250. case 'csunicode':
  12251. case 'iso10646ucs2':
  12252. return 'ISO-10646-UCS-2';
  12253. case 'csucs4':
  12254. case 'iso10646ucs4':
  12255. return 'ISO-10646-UCS-4';
  12256. case 'csunicodeascii':
  12257. case 'iso10646ucsbasic':
  12258. return 'ISO-10646-UCS-Basic';
  12259. case 'csunicodelatin1':
  12260. case 'iso10646':
  12261. case 'iso10646unicodelatin1':
  12262. return 'ISO-10646-Unicode-Latin1';
  12263. case 'csiso10646utf1':
  12264. case 'iso10646utf1':
  12265. return 'ISO-10646-UTF-1';
  12266. case 'csiso115481':
  12267. case 'iso115481':
  12268. case 'isotr115481':
  12269. return 'ISO-11548-1';
  12270. case 'csiso90':
  12271. case 'isoir90':
  12272. return 'iso-ir-90';
  12273. case 'csunicodeibm1261':
  12274. case 'isounicodeibm1261':
  12275. return 'ISO-Unicode-IBM-1261';
  12276. case 'csunicodeibm1264':
  12277. case 'isounicodeibm1264':
  12278. return 'ISO-Unicode-IBM-1264';
  12279. case 'csunicodeibm1265':
  12280. case 'isounicodeibm1265':
  12281. return 'ISO-Unicode-IBM-1265';
  12282. case 'csunicodeibm1268':
  12283. case 'isounicodeibm1268':
  12284. return 'ISO-Unicode-IBM-1268';
  12285. case 'csunicodeibm1276':
  12286. case 'isounicodeibm1276':
  12287. return 'ISO-Unicode-IBM-1276';
  12288. case 'csiso646basic1983':
  12289. case 'iso646basic1983':
  12290. case 'ref':
  12291. return 'ISO_646.basic:1983';
  12292. case 'csiso2intlrefversion':
  12293. case 'irv':
  12294. case 'iso646irv1983':
  12295. case 'isoir2':
  12296. return 'ISO_646.irv:1983';
  12297. case 'csiso2033':
  12298. case 'e13b':
  12299. case 'iso20331983':
  12300. case 'isoir98':
  12301. return 'ISO_2033-1983';
  12302. case 'csiso5427cyrillic':
  12303. case 'iso5427':
  12304. case 'isoir37':
  12305. return 'ISO_5427';
  12306. case 'iso5427cyrillic1981':
  12307. case 'iso54271981':
  12308. case 'isoir54':
  12309. return 'ISO_5427:1981';
  12310. case 'csiso5428greek':
  12311. case 'iso54281980':
  12312. case 'isoir55':
  12313. return 'ISO_5428:1980';
  12314. case 'csiso6937add':
  12315. case 'iso6937225':
  12316. case 'isoir152':
  12317. return 'ISO_6937-2-25';
  12318. case 'csisotextcomm':
  12319. case 'iso69372add':
  12320. case 'isoir142':
  12321. return 'ISO_6937-2-add';
  12322. case 'csiso8859supp':
  12323. case 'iso8859supp':
  12324. case 'isoir154':
  12325. case 'latin125':
  12326. return 'ISO_8859-supp';
  12327. case 'csiso10367box':
  12328. case 'iso10367box':
  12329. case 'isoir155':
  12330. return 'ISO_10367-box';
  12331. case 'csiso15italian':
  12332. case 'iso646it':
  12333. case 'isoir15':
  12334. case 'it':
  12335. return 'IT';
  12336. case 'csiso13jisc6220jp':
  12337. case 'isoir13':
  12338. case 'jisc62201969':
  12339. case 'jisc62201969jp':
  12340. case 'katakana':
  12341. case 'x2017':
  12342. return 'JIS_C6220-1969-jp';
  12343. case 'csiso14jisc6220ro':
  12344. case 'iso646jp':
  12345. case 'isoir14':
  12346. case 'jisc62201969ro':
  12347. case 'jp':
  12348. return 'JIS_C6220-1969-ro';
  12349. case 'csiso42jisc62261978':
  12350. case 'isoir42':
  12351. case 'jisc62261978':
  12352. return 'JIS_C6226-1978';
  12353. case 'csiso87jisx208':
  12354. case 'isoir87':
  12355. case 'jisc62261983':
  12356. case 'jisx2081983':
  12357. case 'x208':
  12358. return 'JIS_C6226-1983';
  12359. case 'csiso91jisc62291984a':
  12360. case 'isoir91':
  12361. case 'jisc62291984a':
  12362. case 'jpocra':
  12363. return 'JIS_C6229-1984-a';
  12364. case 'csiso92jisc62991984b':
  12365. case 'iso646jpocrb':
  12366. case 'isoir92':
  12367. case 'jisc62291984b':
  12368. case 'jpocrb':
  12369. return 'JIS_C6229-1984-b';
  12370. case 'csiso93jis62291984badd':
  12371. case 'isoir93':
  12372. case 'jisc62291984badd':
  12373. case 'jpocrbadd':
  12374. return 'JIS_C6229-1984-b-add';
  12375. case 'csiso94jis62291984hand':
  12376. case 'isoir94':
  12377. case 'jisc62291984hand':
  12378. case 'jpocrhand':
  12379. return 'JIS_C6229-1984-hand';
  12380. case 'csiso95jis62291984handadd':
  12381. case 'isoir95':
  12382. case 'jisc62291984handadd':
  12383. case 'jpocrhandadd':
  12384. return 'JIS_C6229-1984-hand-add';
  12385. case 'csiso96jisc62291984kana':
  12386. case 'isoir96':
  12387. case 'jisc62291984kana':
  12388. return 'JIS_C6229-1984-kana';
  12389. case 'csjisencoding':
  12390. case 'jisencoding':
  12391. return 'JIS_Encoding';
  12392. case 'cshalfwidthkatakana':
  12393. case 'jisx201':
  12394. case 'x201':
  12395. return 'JIS_X0201';
  12396. case 'csiso159jisx2121990':
  12397. case 'isoir159':
  12398. case 'jisx2121990':
  12399. case 'x212':
  12400. return 'JIS_X0212-1990';
  12401. case 'csiso141jusib1002':
  12402. case 'iso646yu':
  12403. case 'isoir141':
  12404. case 'js':
  12405. case 'jusib1002':
  12406. case 'yu':
  12407. return 'JUS_I.B1.002';
  12408. case 'csiso147macedonian':
  12409. case 'isoir147':
  12410. case 'jusib1003mac':
  12411. case 'macedonian':
  12412. return 'JUS_I.B1.003-mac';
  12413. case 'csiso146serbian':
  12414. case 'isoir146':
  12415. case 'jusib1003serb':
  12416. case 'serbian':
  12417. return 'JUS_I.B1.003-serb';
  12418. case 'koi7switched':
  12419. return 'KOI7-switched';
  12420. case 'cskoi8r':
  12421. case 'koi8r':
  12422. return 'KOI8-R';
  12423. case 'koi8u':
  12424. return 'KOI8-U';
  12425. case 'csksc5636':
  12426. case 'iso646kr':
  12427. case 'ksc5636':
  12428. return 'KSC5636';
  12429. case 'cskz1048':
  12430. case 'kz1048':
  12431. case 'rk1048':
  12432. case 'strk10482002':
  12433. return 'KZ-1048';
  12434. case 'csiso19latingreek':
  12435. case 'isoir19':
  12436. case 'latingreek':
  12437. return 'latin-greek';
  12438. case 'csiso27latingreek1':
  12439. case 'isoir27':
  12440. case 'latingreek1':
  12441. return 'Latin-greek-1';
  12442. case 'csiso158lap':
  12443. case 'isoir158':
  12444. case 'lap':
  12445. case 'latinlap':
  12446. return 'latin-lap';
  12447. case 'csmacintosh':
  12448. case 'mac':
  12449. case 'macintosh':
  12450. return 'macintosh';
  12451. case 'csmicrosoftpublishing':
  12452. case 'microsoftpublishing':
  12453. return 'Microsoft-Publishing';
  12454. case 'csmnem':
  12455. case 'mnem':
  12456. return 'MNEM';
  12457. case 'csmnemonic':
  12458. case 'mnemonic':
  12459. return 'MNEMONIC';
  12460. case 'csiso86hungarian':
  12461. case 'hu':
  12462. case 'iso646hu':
  12463. case 'isoir86':
  12464. case 'msz77953':
  12465. return 'MSZ_7795.3';
  12466. case 'csnatsdano':
  12467. case 'isoir91':
  12468. case 'natsdano':
  12469. return 'NATS-DANO';
  12470. case 'csnatsdanoadd':
  12471. case 'isoir92':
  12472. case 'natsdanoadd':
  12473. return 'NATS-DANO-ADD';
  12474. case 'csnatssefi':
  12475. case 'isoir81':
  12476. case 'natssefi':
  12477. return 'NATS-SEFI';
  12478. case 'csnatssefiadd':
  12479. case 'isoir82':
  12480. case 'natssefiadd':
  12481. return 'NATS-SEFI-ADD';
  12482. case 'csiso151cuba':
  12483. case 'cuba':
  12484. case 'iso646cu':
  12485. case 'isoir151':
  12486. case 'ncnc1081':
  12487. return 'NC_NC00-10:81';
  12488. case 'csiso69french':
  12489. case 'fr':
  12490. case 'iso646fr':
  12491. case 'isoir69':
  12492. case 'nfz62010':
  12493. return 'NF_Z_62-010';
  12494. case 'csiso25french':
  12495. case 'iso646fr1':
  12496. case 'isoir25':
  12497. case 'nfz620101973':
  12498. return 'NF_Z_62-010_(1973)';
  12499. case 'csiso60danishnorwegian':
  12500. case 'csiso60norwegian1':
  12501. case 'iso646no':
  12502. case 'isoir60':
  12503. case 'no':
  12504. case 'ns45511':
  12505. return 'NS_4551-1';
  12506. case 'csiso61norwegian2':
  12507. case 'iso646no2':
  12508. case 'isoir61':
  12509. case 'no2':
  12510. case 'ns45512':
  12511. return 'NS_4551-2';
  12512. case 'osdebcdicdf3irv':
  12513. return 'OSD_EBCDIC_DF03_IRV';
  12514. case 'osdebcdicdf41':
  12515. return 'OSD_EBCDIC_DF04_1';
  12516. case 'osdebcdicdf415':
  12517. return 'OSD_EBCDIC_DF04_15';
  12518. case 'cspc8danishnorwegian':
  12519. case 'pc8danishnorwegian':
  12520. return 'PC8-Danish-Norwegian';
  12521. case 'cspc8turkish':
  12522. case 'pc8turkish':
  12523. return 'PC8-Turkish';
  12524. case 'csiso16portuguese':
  12525. case 'iso646pt':
  12526. case 'isoir16':
  12527. case 'pt':
  12528. return 'PT';
  12529. case 'csiso84portuguese2':
  12530. case 'iso646pt2':
  12531. case 'isoir84':
  12532. case 'pt2':
  12533. return 'PT2';
  12534. case 'cp154':
  12535. case 'csptcp154':
  12536. case 'cyrillicasian':
  12537. case 'pt154':
  12538. case 'ptcp154':
  12539. return 'PTCP154';
  12540. case 'scsu':
  12541. return 'SCSU';
  12542. case 'csiso10swedish':
  12543. case 'fi':
  12544. case 'iso646fi':
  12545. case 'iso646se':
  12546. case 'isoir10':
  12547. case 'se':
  12548. case 'sen850200b':
  12549. return 'SEN_850200_B';
  12550. case 'csiso11swedishfornames':
  12551. case 'iso646se2':
  12552. case 'isoir11':
  12553. case 'se2':
  12554. case 'sen850200c':
  12555. return 'SEN_850200_C';
  12556. case 'csiso102t617bit':
  12557. case 'isoir102':
  12558. case 't617bit':
  12559. return 'T.61-7bit';
  12560. case 'csiso103t618bit':
  12561. case 'isoir103':
  12562. case 't61':
  12563. case 't618bit':
  12564. return 'T.61-8bit';
  12565. case 'csiso128t101g2':
  12566. case 'isoir128':
  12567. case 't101g2':
  12568. return 'T.101-G2';
  12569. case 'cstscii':
  12570. case 'tscii':
  12571. return 'TSCII';
  12572. case 'csunicode11':
  12573. case 'unicode11':
  12574. return 'UNICODE-1-1';
  12575. case 'csunicode11utf7':
  12576. case 'unicode11utf7':
  12577. return 'UNICODE-1-1-UTF-7';
  12578. case 'csunknown8bit':
  12579. case 'unknown8bit':
  12580. return 'UNKNOWN-8BIT';
  12581. case 'ansix341968':
  12582. case 'ansix341986':
  12583. case 'ascii':
  12584. case 'cp367':
  12585. case 'csascii':
  12586. case 'ibm367':
  12587. case 'iso646irv1991':
  12588. case 'iso646us':
  12589. case 'isoir6':
  12590. case 'us':
  12591. case 'usascii':
  12592. return 'US-ASCII';
  12593. case 'csusdk':
  12594. case 'usdk':
  12595. return 'us-dk';
  12596. case 'utf7':
  12597. return 'UTF-7';
  12598. case 'utf8':
  12599. return 'UTF-8';
  12600. case 'utf16':
  12601. return 'UTF-16';
  12602. case 'utf16be':
  12603. return 'UTF-16BE';
  12604. case 'utf16le':
  12605. return 'UTF-16LE';
  12606. case 'utf32':
  12607. return 'UTF-32';
  12608. case 'utf32be':
  12609. return 'UTF-32BE';
  12610. case 'utf32le':
  12611. return 'UTF-32LE';
  12612. case 'csventurainternational':
  12613. case 'venturainternational':
  12614. return 'Ventura-International';
  12615. case 'csventuramath':
  12616. case 'venturamath':
  12617. return 'Ventura-Math';
  12618. case 'csventuraus':
  12619. case 'venturaus':
  12620. return 'Ventura-US';
  12621. case 'csiso70videotexsupp1':
  12622. case 'isoir70':
  12623. case 'videotexsuppl':
  12624. return 'videotex-suppl';
  12625. case 'csviqr':
  12626. case 'viqr':
  12627. return 'VIQR';
  12628. case 'csviscii':
  12629. case 'viscii':
  12630. return 'VISCII';
  12631. case 'csshiftjis':
  12632. case 'cswindows31j':
  12633. case 'mskanji':
  12634. case 'shiftjis':
  12635. case 'windows31j':
  12636. return 'Windows-31J';
  12637. case 'iso885911':
  12638. case 'tis620':
  12639. return 'windows-874';
  12640. case 'cseuckr':
  12641. case 'csksc56011987':
  12642. case 'euckr':
  12643. case 'isoir149':
  12644. case 'korean':
  12645. case 'ksc5601':
  12646. case 'ksc56011987':
  12647. case 'ksc56011989':
  12648. case 'windows949':
  12649. return 'windows-949';
  12650. case 'windows1250':
  12651. return 'windows-1250';
  12652. case 'windows1251':
  12653. return 'windows-1251';
  12654. case 'cp819':
  12655. case 'csisolatin1':
  12656. case 'ibm819':
  12657. case 'iso88591':
  12658. case 'iso885911987':
  12659. case 'isoir100':
  12660. case 'l1':
  12661. case 'latin1':
  12662. case 'windows1252':
  12663. return 'windows-1252';
  12664. case 'windows1253':
  12665. return 'windows-1253';
  12666. case 'csisolatin5':
  12667. case 'iso88599':
  12668. case 'iso885991989':
  12669. case 'isoir148':
  12670. case 'l5':
  12671. case 'latin5':
  12672. case 'windows1254':
  12673. return 'windows-1254';
  12674. case 'windows1255':
  12675. return 'windows-1255';
  12676. case 'windows1256':
  12677. return 'windows-1256';
  12678. case 'windows1257':
  12679. return 'windows-1257';
  12680. case 'windows1258':
  12681. return 'windows-1258';
  12682. default:
  12683. return $charset;
  12684. }
  12685. }
  12686. public static function get_curl_version()
  12687. {
  12688. if (is_array($curl = curl_version()))
  12689. {
  12690. $curl = $curl['version'];
  12691. }
  12692. elseif (substr($curl, 0, 5) === 'curl/')
  12693. {
  12694. $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
  12695. }
  12696. elseif (substr($curl, 0, 8) === 'libcurl/')
  12697. {
  12698. $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
  12699. }
  12700. else
  12701. {
  12702. $curl = 0;
  12703. }
  12704. return $curl;
  12705. }
  12706. /**
  12707. * Strip HTML comments
  12708. *
  12709. * @param string $data Data to strip comments from
  12710. * @return string Comment stripped string
  12711. */
  12712. public static function strip_comments($data)
  12713. {
  12714. $output = '';
  12715. while (($start = strpos($data, '<!--')) !== false)
  12716. {
  12717. $output .= substr($data, 0, $start);
  12718. if (($end = strpos($data, '-->', $start)) !== false)
  12719. {
  12720. $data = substr_replace($data, '', 0, $end + 3);
  12721. }
  12722. else
  12723. {
  12724. $data = '';
  12725. }
  12726. }
  12727. return $output . $data;
  12728. }
  12729. public static function parse_date($dt)
  12730. {
  12731. $parser = SimplePie_Parse_Date::get();
  12732. return $parser->parse($dt);
  12733. }
  12734. /**
  12735. * Decode HTML entities
  12736. *
  12737. * @deprecated Use DOMDocument instead
  12738. * @param string $data Input data
  12739. * @return string Output data
  12740. */
  12741. public static function entities_decode($data)
  12742. {
  12743. $decoder = new SimplePie_Decode_HTML_Entities($data);
  12744. return $decoder->parse();
  12745. }
  12746. /**
  12747. * Remove RFC822 comments
  12748. *
  12749. * @param string $data Data to strip comments from
  12750. * @return string Comment stripped string
  12751. */
  12752. public static function uncomment_rfc822($string)
  12753. {
  12754. $string = (string) $string;
  12755. $position = 0;
  12756. $length = strlen($string);
  12757. $depth = 0;
  12758. $output = '';
  12759. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  12760. {
  12761. $output .= substr($string, $position, $pos - $position);
  12762. $position = $pos + 1;
  12763. if ($string[$pos - 1] !== '\\')
  12764. {
  12765. $depth++;
  12766. while ($depth && $position < $length)
  12767. {
  12768. $position += strcspn($string, '()', $position);
  12769. if ($string[$position - 1] === '\\')
  12770. {
  12771. $position++;
  12772. continue;
  12773. }
  12774. elseif (isset($string[$position]))
  12775. {
  12776. switch ($string[$position])
  12777. {
  12778. case '(':
  12779. $depth++;
  12780. break;
  12781. case ')':
  12782. $depth--;
  12783. break;
  12784. }
  12785. $position++;
  12786. }
  12787. else
  12788. {
  12789. break;
  12790. }
  12791. }
  12792. }
  12793. else
  12794. {
  12795. $output .= '(';
  12796. }
  12797. }
  12798. $output .= substr($string, $position);
  12799. return $output;
  12800. }
  12801. public static function parse_mime($mime)
  12802. {
  12803. if (($pos = strpos($mime, ';')) === false)
  12804. {
  12805. return trim($mime);
  12806. }
  12807. else
  12808. {
  12809. return trim(substr($mime, 0, $pos));
  12810. }
  12811. }
  12812. public static function atom_03_construct_type($attribs)
  12813. {
  12814. if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
  12815. {
  12816. $mode = SIMPLEPIE_CONSTRUCT_BASE64;
  12817. }
  12818. else
  12819. {
  12820. $mode = SIMPLEPIE_CONSTRUCT_NONE;
  12821. }
  12822. if (isset($attribs['']['type']))
  12823. {
  12824. switch (strtolower(trim($attribs['']['type'])))
  12825. {
  12826. case 'text':
  12827. case 'text/plain':
  12828. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  12829. case 'html':
  12830. case 'text/html':
  12831. return SIMPLEPIE_CONSTRUCT_HTML | $mode;
  12832. case 'xhtml':
  12833. case 'application/xhtml+xml':
  12834. return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
  12835. default:
  12836. return SIMPLEPIE_CONSTRUCT_NONE | $mode;
  12837. }
  12838. }
  12839. else
  12840. {
  12841. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  12842. }
  12843. }
  12844. public static function atom_10_construct_type($attribs)
  12845. {
  12846. if (isset($attribs['']['type']))
  12847. {
  12848. switch (strtolower(trim($attribs['']['type'])))
  12849. {
  12850. case 'text':
  12851. return SIMPLEPIE_CONSTRUCT_TEXT;
  12852. case 'html':
  12853. return SIMPLEPIE_CONSTRUCT_HTML;
  12854. case 'xhtml':
  12855. return SIMPLEPIE_CONSTRUCT_XHTML;
  12856. default:
  12857. return SIMPLEPIE_CONSTRUCT_NONE;
  12858. }
  12859. }
  12860. return SIMPLEPIE_CONSTRUCT_TEXT;
  12861. }
  12862. public static function atom_10_content_construct_type($attribs)
  12863. {
  12864. if (isset($attribs['']['type']))
  12865. {
  12866. $type = strtolower(trim($attribs['']['type']));
  12867. switch ($type)
  12868. {
  12869. case 'text':
  12870. return SIMPLEPIE_CONSTRUCT_TEXT;
  12871. case 'html':
  12872. return SIMPLEPIE_CONSTRUCT_HTML;
  12873. case 'xhtml':
  12874. return SIMPLEPIE_CONSTRUCT_XHTML;
  12875. }
  12876. if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
  12877. {
  12878. return SIMPLEPIE_CONSTRUCT_NONE;
  12879. }
  12880. else
  12881. {
  12882. return SIMPLEPIE_CONSTRUCT_BASE64;
  12883. }
  12884. }
  12885. else
  12886. {
  12887. return SIMPLEPIE_CONSTRUCT_TEXT;
  12888. }
  12889. }
  12890. public static function is_isegment_nz_nc($string)
  12891. {
  12892. 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);
  12893. }
  12894. public static function space_seperated_tokens($string)
  12895. {
  12896. $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
  12897. $string_length = strlen($string);
  12898. $position = strspn($string, $space_characters);
  12899. $tokens = array();
  12900. while ($position < $string_length)
  12901. {
  12902. $len = strcspn($string, $space_characters, $position);
  12903. $tokens[] = substr($string, $position, $len);
  12904. $position += $len;
  12905. $position += strspn($string, $space_characters, $position);
  12906. }
  12907. return $tokens;
  12908. }
  12909. /**
  12910. * Converts a unicode codepoint to a UTF-8 character
  12911. *
  12912. * @static
  12913. * @param int $codepoint Unicode codepoint
  12914. * @return string UTF-8 character
  12915. */
  12916. public static function codepoint_to_utf8($codepoint)
  12917. {
  12918. $codepoint = (int) $codepoint;
  12919. if ($codepoint < 0)
  12920. {
  12921. return false;
  12922. }
  12923. else if ($codepoint <= 0x7f)
  12924. {
  12925. return chr($codepoint);
  12926. }
  12927. else if ($codepoint <= 0x7ff)
  12928. {
  12929. return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
  12930. }
  12931. else if ($codepoint <= 0xffff)
  12932. {
  12933. return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  12934. }
  12935. else if ($codepoint <= 0x10ffff)
  12936. {
  12937. return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  12938. }
  12939. else
  12940. {
  12941. // U+FFFD REPLACEMENT CHARACTER
  12942. return "\xEF\xBF\xBD";
  12943. }
  12944. }
  12945. /**
  12946. * Similar to parse_str()
  12947. *
  12948. * Returns an associative array of name/value pairs, where the value is an
  12949. * array of values that have used the same name
  12950. *
  12951. * @static
  12952. * @param string $str The input string.
  12953. * @return array
  12954. */
  12955. public static function parse_str($str)
  12956. {
  12957. $return = array();
  12958. $str = explode('&', $str);
  12959. foreach ($str as $section)
  12960. {
  12961. if (strpos($section, '=') !== false)
  12962. {
  12963. list($name, $value) = explode('=', $section, 2);
  12964. $return[urldecode($name)][] = urldecode($value);
  12965. }
  12966. else
  12967. {
  12968. $return[urldecode($section)][] = null;
  12969. }
  12970. }
  12971. return $return;
  12972. }
  12973. /**
  12974. * Detect XML encoding, as per XML 1.0 Appendix F.1
  12975. *
  12976. * @todo Add support for EBCDIC
  12977. * @param string $data XML data
  12978. * @param SimplePie_Registry $registry Class registry
  12979. * @return array Possible encodings
  12980. */
  12981. public static function xml_encoding($data, $registry)
  12982. {
  12983. // UTF-32 Big Endian BOM
  12984. if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
  12985. {
  12986. $encoding[] = 'UTF-32BE';
  12987. }
  12988. // UTF-32 Little Endian BOM
  12989. elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
  12990. {
  12991. $encoding[] = 'UTF-32LE';
  12992. }
  12993. // UTF-16 Big Endian BOM
  12994. elseif (substr($data, 0, 2) === "\xFE\xFF")
  12995. {
  12996. $encoding[] = 'UTF-16BE';
  12997. }
  12998. // UTF-16 Little Endian BOM
  12999. elseif (substr($data, 0, 2) === "\xFF\xFE")
  13000. {
  13001. $encoding[] = 'UTF-16LE';
  13002. }
  13003. // UTF-8 BOM
  13004. elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
  13005. {
  13006. $encoding[] = 'UTF-8';
  13007. }
  13008. // UTF-32 Big Endian Without BOM
  13009. 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")
  13010. {
  13011. if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
  13012. {
  13013. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
  13014. if ($parser->parse())
  13015. {
  13016. $encoding[] = $parser->encoding;
  13017. }
  13018. }
  13019. $encoding[] = 'UTF-32BE';
  13020. }
  13021. // UTF-32 Little Endian Without BOM
  13022. 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")
  13023. {
  13024. if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
  13025. {
  13026. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
  13027. if ($parser->parse())
  13028. {
  13029. $encoding[] = $parser->encoding;
  13030. }
  13031. }
  13032. $encoding[] = 'UTF-32LE';
  13033. }
  13034. // UTF-16 Big Endian Without BOM
  13035. elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
  13036. {
  13037. if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
  13038. {
  13039. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
  13040. if ($parser->parse())
  13041. {
  13042. $encoding[] = $parser->encoding;
  13043. }
  13044. }
  13045. $encoding[] = 'UTF-16BE';
  13046. }
  13047. // UTF-16 Little Endian Without BOM
  13048. elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
  13049. {
  13050. if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
  13051. {
  13052. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
  13053. if ($parser->parse())
  13054. {
  13055. $encoding[] = $parser->encoding;
  13056. }
  13057. }
  13058. $encoding[] = 'UTF-16LE';
  13059. }
  13060. // US-ASCII (or superset)
  13061. elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
  13062. {
  13063. if ($pos = strpos($data, "\x3F\x3E"))
  13064. {
  13065. $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
  13066. if ($parser->parse())
  13067. {
  13068. $encoding[] = $parser->encoding;
  13069. }
  13070. }
  13071. $encoding[] = 'UTF-8';
  13072. }
  13073. // Fallback to UTF-8
  13074. else
  13075. {
  13076. $encoding[] = 'UTF-8';
  13077. }
  13078. return $encoding;
  13079. }
  13080. public static function output_javascript()
  13081. {
  13082. if (function_exists('ob_gzhandler'))
  13083. {
  13084. ob_start('ob_gzhandler');
  13085. }
  13086. header('Content-type: text/javascript; charset: UTF-8');
  13087. header('Cache-Control: must-revalidate');
  13088. header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
  13089. ?>
  13090. function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
  13091. if (placeholder != '') {
  13092. 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>');
  13093. }
  13094. else {
  13095. 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>');
  13096. }
  13097. }
  13098. function embed_flash(bgcolor, width, height, link, loop, type) {
  13099. 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>');
  13100. }
  13101. function embed_flv(width, height, link, placeholder, loop, player) {
  13102. 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>');
  13103. }
  13104. function embed_wmedia(width, height, link) {
  13105. document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
  13106. }
  13107. <?php
  13108. }
  13109. /**
  13110. * Get the SimplePie build timestamp
  13111. *
  13112. * Uses the git index if it exists, otherwise uses the modification time
  13113. * of the newest file.
  13114. */
  13115. public static function get_build()
  13116. {
  13117. $root = dirname(dirname(__FILE__));
  13118. if (file_exists($root . '/.git/index'))
  13119. {
  13120. return filemtime($root . '/.git/index');
  13121. }
  13122. elseif (file_exists($root . '/SimplePie'))
  13123. {
  13124. $time = 0;
  13125. foreach (glob($root . '/SimplePie/*.php') as $file)
  13126. {
  13127. if (($mtime = filemtime($file)) > $time)
  13128. {
  13129. $time = $mtime;
  13130. }
  13131. }
  13132. return $time;
  13133. }
  13134. elseif (file_exists(dirname(__FILE__) . '/Core.php'))
  13135. {
  13136. return filemtime(dirname(__FILE__) . '/Core.php');
  13137. }
  13138. else
  13139. {
  13140. return filemtime(__FILE__);
  13141. }
  13142. }
  13143. /**
  13144. * Format debugging information
  13145. */
  13146. public static function debug(&$sp)
  13147. {
  13148. $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
  13149. $info .= 'PHP ' . PHP_VERSION . "\n";
  13150. if ($sp->error() !== null)
  13151. {
  13152. $info .= 'Error occurred: ' . $sp->error() . "\n";
  13153. }
  13154. else
  13155. {
  13156. $info .= "No error found.\n";
  13157. }
  13158. $info .= "Extensions:\n";
  13159. $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
  13160. foreach ($extensions as $ext)
  13161. {
  13162. if (extension_loaded($ext))
  13163. {
  13164. $info .= " $ext loaded\n";
  13165. switch ($ext)
  13166. {
  13167. case 'pcre':
  13168. $info .= ' Version ' . PCRE_VERSION . "\n";
  13169. break;
  13170. case 'curl':
  13171. $version = curl_version();
  13172. $info .= ' Version ' . $version['version'] . "\n";
  13173. break;
  13174. case 'mbstring':
  13175. $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
  13176. break;
  13177. case 'iconv':
  13178. $info .= ' Version ' . ICONV_VERSION . "\n";
  13179. break;
  13180. case 'xml':
  13181. $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
  13182. break;
  13183. }
  13184. }
  13185. else
  13186. {
  13187. $info .= " $ext not loaded\n";
  13188. }
  13189. }
  13190. return $info;
  13191. }
  13192. public static function silence_errors($num, $str)
  13193. {
  13194. // No-op
  13195. }
  13196. }
  13197. /**
  13198. * Class to validate and to work with IPv6 addresses.
  13199. *
  13200. * @package SimplePie
  13201. * @subpackage HTTP
  13202. * @copyright 2003-2005 The PHP Group
  13203. * @license http://www.opensource.org/licenses/bsd-license.php
  13204. * @link http://pear.php.net/package/Net_IPv6
  13205. * @author Alexander Merz <alexander.merz@web.de>
  13206. * @author elfrink at introweb dot nl
  13207. * @author Josh Peck <jmp at joshpeck dot org>
  13208. * @author Geoffrey Sneddon <geoffers@gmail.com>
  13209. */
  13210. class SimplePie_Net_IPv6
  13211. {
  13212. /**
  13213. * Uncompresses an IPv6 address
  13214. *
  13215. * RFC 4291 allows you to compress concecutive zero pieces in an address to
  13216. * '::'. This method expects a valid IPv6 address and expands the '::' to
  13217. * the required number of zero pieces.
  13218. *
  13219. * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
  13220. * ::1 -> 0:0:0:0:0:0:0:1
  13221. *
  13222. * @author Alexander Merz <alexander.merz@web.de>
  13223. * @author elfrink at introweb dot nl
  13224. * @author Josh Peck <jmp at joshpeck dot org>
  13225. * @copyright 2003-2005 The PHP Group
  13226. * @license http://www.opensource.org/licenses/bsd-license.php
  13227. * @param string $ip An IPv6 address
  13228. * @return string The uncompressed IPv6 address
  13229. */
  13230. public static function uncompress($ip)
  13231. {
  13232. $c1 = -1;
  13233. $c2 = -1;
  13234. if (substr_count($ip, '::') === 1)
  13235. {
  13236. list($ip1, $ip2) = explode('::', $ip);
  13237. if ($ip1 === '')
  13238. {
  13239. $c1 = -1;
  13240. }
  13241. else
  13242. {
  13243. $c1 = substr_count($ip1, ':');
  13244. }
  13245. if ($ip2 === '')
  13246. {
  13247. $c2 = -1;
  13248. }
  13249. else
  13250. {
  13251. $c2 = substr_count($ip2, ':');
  13252. }
  13253. if (strpos($ip2, '.') !== false)
  13254. {
  13255. $c2++;
  13256. }
  13257. // ::
  13258. if ($c1 === -1 && $c2 === -1)
  13259. {
  13260. $ip = '0:0:0:0:0:0:0:0';
  13261. }
  13262. // ::xxx
  13263. else if ($c1 === -1)
  13264. {
  13265. $fill = str_repeat('0:', 7 - $c2);
  13266. $ip = str_replace('::', $fill, $ip);
  13267. }
  13268. // xxx::
  13269. else if ($c2 === -1)
  13270. {
  13271. $fill = str_repeat(':0', 7 - $c1);
  13272. $ip = str_replace('::', $fill, $ip);
  13273. }
  13274. // xxx::xxx
  13275. else
  13276. {
  13277. $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
  13278. $ip = str_replace('::', $fill, $ip);
  13279. }
  13280. }
  13281. return $ip;
  13282. }
  13283. /**
  13284. * Compresses an IPv6 address
  13285. *
  13286. * RFC 4291 allows you to compress concecutive zero pieces in an address to
  13287. * '::'. This method expects a valid IPv6 address and compresses consecutive
  13288. * zero pieces to '::'.
  13289. *
  13290. * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
  13291. * 0:0:0:0:0:0:0:1 -> ::1
  13292. *
  13293. * @see uncompress()
  13294. * @param string $ip An IPv6 address
  13295. * @return string The compressed IPv6 address
  13296. */
  13297. public static function compress($ip)
  13298. {
  13299. // Prepare the IP to be compressed
  13300. $ip = self::uncompress($ip);
  13301. $ip_parts = self::split_v6_v4($ip);
  13302. // Replace all leading zeros
  13303. $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
  13304. // Find bunches of zeros
  13305. if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
  13306. {
  13307. $max = 0;
  13308. $pos = null;
  13309. foreach ($matches[0] as $match)
  13310. {
  13311. if (strlen($match[0]) > $max)
  13312. {
  13313. $max = strlen($match[0]);
  13314. $pos = $match[1];
  13315. }
  13316. }
  13317. $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
  13318. }
  13319. if ($ip_parts[1] !== '')
  13320. {
  13321. return implode(':', $ip_parts);
  13322. }
  13323. else
  13324. {
  13325. return $ip_parts[0];
  13326. }
  13327. }
  13328. /**
  13329. * Splits an IPv6 address into the IPv6 and IPv4 representation parts
  13330. *
  13331. * RFC 4291 allows you to represent the last two parts of an IPv6 address
  13332. * using the standard IPv4 representation
  13333. *
  13334. * Example: 0:0:0:0:0:0:13.1.68.3
  13335. * 0:0:0:0:0:FFFF:129.144.52.38
  13336. *
  13337. * @param string $ip An IPv6 address
  13338. * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
  13339. */
  13340. private static function split_v6_v4($ip)
  13341. {
  13342. if (strpos($ip, '.') !== false)
  13343. {
  13344. $pos = strrpos($ip, ':');
  13345. $ipv6_part = substr($ip, 0, $pos);
  13346. $ipv4_part = substr($ip, $pos + 1);
  13347. return array($ipv6_part, $ipv4_part);
  13348. }
  13349. else
  13350. {
  13351. return array($ip, '');
  13352. }
  13353. }
  13354. /**
  13355. * Checks an IPv6 address
  13356. *
  13357. * Checks if the given IP is a valid IPv6 address
  13358. *
  13359. * @param string $ip An IPv6 address
  13360. * @return bool true if $ip is a valid IPv6 address
  13361. */
  13362. public static function check_ipv6($ip)
  13363. {
  13364. $ip = self::uncompress($ip);
  13365. list($ipv6, $ipv4) = self::split_v6_v4($ip);
  13366. $ipv6 = explode(':', $ipv6);
  13367. $ipv4 = explode('.', $ipv4);
  13368. if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
  13369. {
  13370. foreach ($ipv6 as $ipv6_part)
  13371. {
  13372. // The section can't be empty
  13373. if ($ipv6_part === '')
  13374. return false;
  13375. // Nor can it be over four characters
  13376. if (strlen($ipv6_part) > 4)
  13377. return false;
  13378. // Remove leading zeros (this is safe because of the above)
  13379. $ipv6_part = ltrim($ipv6_part, '0');
  13380. if ($ipv6_part === '')
  13381. $ipv6_part = '0';
  13382. // Check the value is valid
  13383. $value = hexdec($ipv6_part);
  13384. if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
  13385. return false;
  13386. }
  13387. if (count($ipv4) === 4)
  13388. {
  13389. foreach ($ipv4 as $ipv4_part)
  13390. {
  13391. $value = (int) $ipv4_part;
  13392. if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
  13393. return false;
  13394. }
  13395. }
  13396. return true;
  13397. }
  13398. else
  13399. {
  13400. return false;
  13401. }
  13402. }
  13403. /**
  13404. * Checks if the given IP is a valid IPv6 address
  13405. *
  13406. * @codeCoverageIgnore
  13407. * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
  13408. * @see check_ipv6
  13409. * @param string $ip An IPv6 address
  13410. * @return bool true if $ip is a valid IPv6 address
  13411. */
  13412. public static function checkIPv6($ip)
  13413. {
  13414. return self::check_ipv6($ip);
  13415. }
  13416. }
  13417. /**
  13418. * Date Parser
  13419. *
  13420. * @package SimplePie
  13421. * @subpackage Parsing
  13422. */
  13423. class SimplePie_Parse_Date
  13424. {
  13425. /**
  13426. * Input data
  13427. *
  13428. * @access protected
  13429. * @var string
  13430. */
  13431. var $date;
  13432. /**
  13433. * List of days, calendar day name => ordinal day number in the week
  13434. *
  13435. * @access protected
  13436. * @var array
  13437. */
  13438. var $day = array(
  13439. // English
  13440. 'mon' => 1,
  13441. 'monday' => 1,
  13442. 'tue' => 2,
  13443. 'tuesday' => 2,
  13444. 'wed' => 3,
  13445. 'wednesday' => 3,
  13446. 'thu' => 4,
  13447. 'thursday' => 4,
  13448. 'fri' => 5,
  13449. 'friday' => 5,
  13450. 'sat' => 6,
  13451. 'saturday' => 6,
  13452. 'sun' => 7,
  13453. 'sunday' => 7,
  13454. // Dutch
  13455. 'maandag' => 1,
  13456. 'dinsdag' => 2,
  13457. 'woensdag' => 3,
  13458. 'donderdag' => 4,
  13459. 'vrijdag' => 5,
  13460. 'zaterdag' => 6,
  13461. 'zondag' => 7,
  13462. // French
  13463. 'lundi' => 1,
  13464. 'mardi' => 2,
  13465. 'mercredi' => 3,
  13466. 'jeudi' => 4,
  13467. 'vendredi' => 5,
  13468. 'samedi' => 6,
  13469. 'dimanche' => 7,
  13470. // German
  13471. 'montag' => 1,
  13472. 'dienstag' => 2,
  13473. 'mittwoch' => 3,
  13474. 'donnerstag' => 4,
  13475. 'freitag' => 5,
  13476. 'samstag' => 6,
  13477. 'sonnabend' => 6,
  13478. 'sonntag' => 7,
  13479. // Italian
  13480. 'lunedì' => 1,
  13481. 'martedì' => 2,
  13482. 'mercoledì' => 3,
  13483. 'giovedì' => 4,
  13484. 'venerdì' => 5,
  13485. 'sabato' => 6,
  13486. 'domenica' => 7,
  13487. // Spanish
  13488. 'lunes' => 1,
  13489. 'martes' => 2,
  13490. 'miércoles' => 3,
  13491. 'jueves' => 4,
  13492. 'viernes' => 5,
  13493. 'sábado' => 6,
  13494. 'domingo' => 7,
  13495. // Finnish
  13496. 'maanantai' => 1,
  13497. 'tiistai' => 2,
  13498. 'keskiviikko' => 3,
  13499. 'torstai' => 4,
  13500. 'perjantai' => 5,
  13501. 'lauantai' => 6,
  13502. 'sunnuntai' => 7,
  13503. // Hungarian
  13504. 'hétfő' => 1,
  13505. 'kedd' => 2,
  13506. 'szerda' => 3,
  13507. 'csütörtok' => 4,
  13508. 'péntek' => 5,
  13509. 'szombat' => 6,
  13510. 'vasárnap' => 7,
  13511. // Greek
  13512. 'Δευ' => 1,
  13513. 'Τρι' => 2,
  13514. 'Τετ' => 3,
  13515. 'Πεμ' => 4,
  13516. 'Παρ' => 5,
  13517. 'Σαβ' => 6,
  13518. 'Κυρ' => 7,
  13519. );
  13520. /**
  13521. * List of months, calendar month name => calendar month number
  13522. *
  13523. * @access protected
  13524. * @var array
  13525. */
  13526. var $month = array(
  13527. // English
  13528. 'jan' => 1,
  13529. 'january' => 1,
  13530. 'feb' => 2,
  13531. 'february' => 2,
  13532. 'mar' => 3,
  13533. 'march' => 3,
  13534. 'apr' => 4,
  13535. 'april' => 4,
  13536. 'may' => 5,
  13537. // No long form of May
  13538. 'jun' => 6,
  13539. 'june' => 6,
  13540. 'jul' => 7,
  13541. 'july' => 7,
  13542. 'aug' => 8,
  13543. 'august' => 8,
  13544. 'sep' => 9,
  13545. 'september' => 8,
  13546. 'oct' => 10,
  13547. 'october' => 10,
  13548. 'nov' => 11,
  13549. 'november' => 11,
  13550. 'dec' => 12,
  13551. 'december' => 12,
  13552. // Dutch
  13553. 'januari' => 1,
  13554. 'februari' => 2,
  13555. 'maart' => 3,
  13556. 'april' => 4,
  13557. 'mei' => 5,
  13558. 'juni' => 6,
  13559. 'juli' => 7,
  13560. 'augustus' => 8,
  13561. 'september' => 9,
  13562. 'oktober' => 10,
  13563. 'november' => 11,
  13564. 'december' => 12,
  13565. // French
  13566. 'janvier' => 1,
  13567. 'février' => 2,
  13568. 'mars' => 3,
  13569. 'avril' => 4,
  13570. 'mai' => 5,
  13571. 'juin' => 6,
  13572. 'juillet' => 7,
  13573. 'août' => 8,
  13574. 'septembre' => 9,
  13575. 'octobre' => 10,
  13576. 'novembre' => 11,
  13577. 'décembre' => 12,
  13578. // German
  13579. 'januar' => 1,
  13580. 'februar' => 2,
  13581. 'märz' => 3,
  13582. 'april' => 4,
  13583. 'mai' => 5,
  13584. 'juni' => 6,
  13585. 'juli' => 7,
  13586. 'august' => 8,
  13587. 'september' => 9,
  13588. 'oktober' => 10,
  13589. 'november' => 11,
  13590. 'dezember' => 12,
  13591. // Italian
  13592. 'gennaio' => 1,
  13593. 'febbraio' => 2,
  13594. 'marzo' => 3,
  13595. 'aprile' => 4,
  13596. 'maggio' => 5,
  13597. 'giugno' => 6,
  13598. 'luglio' => 7,
  13599. 'agosto' => 8,
  13600. 'settembre' => 9,
  13601. 'ottobre' => 10,
  13602. 'novembre' => 11,
  13603. 'dicembre' => 12,
  13604. // Spanish
  13605. 'enero' => 1,
  13606. 'febrero' => 2,
  13607. 'marzo' => 3,
  13608. 'abril' => 4,
  13609. 'mayo' => 5,
  13610. 'junio' => 6,
  13611. 'julio' => 7,
  13612. 'agosto' => 8,
  13613. 'septiembre' => 9,
  13614. 'setiembre' => 9,
  13615. 'octubre' => 10,
  13616. 'noviembre' => 11,
  13617. 'diciembre' => 12,
  13618. // Finnish
  13619. 'tammikuu' => 1,
  13620. 'helmikuu' => 2,
  13621. 'maaliskuu' => 3,
  13622. 'huhtikuu' => 4,
  13623. 'toukokuu' => 5,
  13624. 'kesäkuu' => 6,
  13625. 'heinäkuu' => 7,
  13626. 'elokuu' => 8,
  13627. 'suuskuu' => 9,
  13628. 'lokakuu' => 10,
  13629. 'marras' => 11,
  13630. 'joulukuu' => 12,
  13631. // Hungarian
  13632. 'január' => 1,
  13633. 'február' => 2,
  13634. 'március' => 3,
  13635. 'április' => 4,
  13636. 'május' => 5,
  13637. 'június' => 6,
  13638. 'július' => 7,
  13639. 'augusztus' => 8,
  13640. 'szeptember' => 9,
  13641. 'október' => 10,
  13642. 'november' => 11,
  13643. 'december' => 12,
  13644. // Greek
  13645. 'Ιαν' => 1,
  13646. 'Φεβ' => 2,
  13647. 'Μάώ' => 3,
  13648. 'Μαώ' => 3,
  13649. 'Απρ' => 4,
  13650. 'Μάι' => 5,
  13651. 'Μαϊ' => 5,
  13652. 'Μαι' => 5,
  13653. 'Ιούν' => 6,
  13654. 'Ιον' => 6,
  13655. 'Ιούλ' => 7,
  13656. 'Ιολ' => 7,
  13657. 'Αύγ' => 8,
  13658. 'Αυγ' => 8,
  13659. 'Σεπ' => 9,
  13660. 'Οκτ' => 10,
  13661. 'Νοέ' => 11,
  13662. 'Δεκ' => 12,
  13663. );
  13664. /**
  13665. * List of timezones, abbreviation => offset from UTC
  13666. *
  13667. * @access protected
  13668. * @var array
  13669. */
  13670. var $timezone = array(
  13671. 'ACDT' => 37800,
  13672. 'ACIT' => 28800,
  13673. 'ACST' => 34200,
  13674. 'ACT' => -18000,
  13675. 'ACWDT' => 35100,
  13676. 'ACWST' => 31500,
  13677. 'AEDT' => 39600,
  13678. 'AEST' => 36000,
  13679. 'AFT' => 16200,
  13680. 'AKDT' => -28800,
  13681. 'AKST' => -32400,
  13682. 'AMDT' => 18000,
  13683. 'AMT' => -14400,
  13684. 'ANAST' => 46800,
  13685. 'ANAT' => 43200,
  13686. 'ART' => -10800,
  13687. 'AZOST' => -3600,
  13688. 'AZST' => 18000,
  13689. 'AZT' => 14400,
  13690. 'BIOT' => 21600,
  13691. 'BIT' => -43200,
  13692. 'BOT' => -14400,
  13693. 'BRST' => -7200,
  13694. 'BRT' => -10800,
  13695. 'BST' => 3600,
  13696. 'BTT' => 21600,
  13697. 'CAST' => 18000,
  13698. 'CAT' => 7200,
  13699. 'CCT' => 23400,
  13700. 'CDT' => -18000,
  13701. 'CEDT' => 7200,
  13702. 'CET' => 3600,
  13703. 'CGST' => -7200,
  13704. 'CGT' => -10800,
  13705. 'CHADT' => 49500,
  13706. 'CHAST' => 45900,
  13707. 'CIST' => -28800,
  13708. 'CKT' => -36000,
  13709. 'CLDT' => -10800,
  13710. 'CLST' => -14400,
  13711. 'COT' => -18000,
  13712. 'CST' => -21600,
  13713. 'CVT' => -3600,
  13714. 'CXT' => 25200,
  13715. 'DAVT' => 25200,
  13716. 'DTAT' => 36000,
  13717. 'EADT' => -18000,
  13718. 'EAST' => -21600,
  13719. 'EAT' => 10800,
  13720. 'ECT' => -18000,
  13721. 'EDT' => -14400,
  13722. 'EEST' => 10800,
  13723. 'EET' => 7200,
  13724. 'EGT' => -3600,
  13725. 'EKST' => 21600,
  13726. 'EST' => -18000,
  13727. 'FJT' => 43200,
  13728. 'FKDT' => -10800,
  13729. 'FKST' => -14400,
  13730. 'FNT' => -7200,
  13731. 'GALT' => -21600,
  13732. 'GEDT' => 14400,
  13733. 'GEST' => 10800,
  13734. 'GFT' => -10800,
  13735. 'GILT' => 43200,
  13736. 'GIT' => -32400,
  13737. 'GST' => 14400,
  13738. 'GST' => -7200,
  13739. 'GYT' => -14400,
  13740. 'HAA' => -10800,
  13741. 'HAC' => -18000,
  13742. 'HADT' => -32400,
  13743. 'HAE' => -14400,
  13744. 'HAP' => -25200,
  13745. 'HAR' => -21600,
  13746. 'HAST' => -36000,
  13747. 'HAT' => -9000,
  13748. 'HAY' => -28800,
  13749. 'HKST' => 28800,
  13750. 'HMT' => 18000,
  13751. 'HNA' => -14400,
  13752. 'HNC' => -21600,
  13753. 'HNE' => -18000,
  13754. 'HNP' => -28800,
  13755. 'HNR' => -25200,
  13756. 'HNT' => -12600,
  13757. 'HNY' => -32400,
  13758. 'IRDT' => 16200,
  13759. 'IRKST' => 32400,
  13760. 'IRKT' => 28800,
  13761. 'IRST' => 12600,
  13762. 'JFDT' => -10800,
  13763. 'JFST' => -14400,
  13764. 'JST' => 32400,
  13765. 'KGST' => 21600,
  13766. 'KGT' => 18000,
  13767. 'KOST' => 39600,
  13768. 'KOVST' => 28800,
  13769. 'KOVT' => 25200,
  13770. 'KRAST' => 28800,
  13771. 'KRAT' => 25200,
  13772. 'KST' => 32400,
  13773. 'LHDT' => 39600,
  13774. 'LHST' => 37800,
  13775. 'LINT' => 50400,
  13776. 'LKT' => 21600,
  13777. 'MAGST' => 43200,
  13778. 'MAGT' => 39600,
  13779. 'MAWT' => 21600,
  13780. 'MDT' => -21600,
  13781. 'MESZ' => 7200,
  13782. 'MEZ' => 3600,
  13783. 'MHT' => 43200,
  13784. 'MIT' => -34200,
  13785. 'MNST' => 32400,
  13786. 'MSDT' => 14400,
  13787. 'MSST' => 10800,
  13788. 'MST' => -25200,
  13789. 'MUT' => 14400,
  13790. 'MVT' => 18000,
  13791. 'MYT' => 28800,
  13792. 'NCT' => 39600,
  13793. 'NDT' => -9000,
  13794. 'NFT' => 41400,
  13795. 'NMIT' => 36000,
  13796. 'NOVST' => 25200,
  13797. 'NOVT' => 21600,
  13798. 'NPT' => 20700,
  13799. 'NRT' => 43200,
  13800. 'NST' => -12600,
  13801. 'NUT' => -39600,
  13802. 'NZDT' => 46800,
  13803. 'NZST' => 43200,
  13804. 'OMSST' => 25200,
  13805. 'OMST' => 21600,
  13806. 'PDT' => -25200,
  13807. 'PET' => -18000,
  13808. 'PETST' => 46800,
  13809. 'PETT' => 43200,
  13810. 'PGT' => 36000,
  13811. 'PHOT' => 46800,
  13812. 'PHT' => 28800,
  13813. 'PKT' => 18000,
  13814. 'PMDT' => -7200,
  13815. 'PMST' => -10800,
  13816. 'PONT' => 39600,
  13817. 'PST' => -28800,
  13818. 'PWT' => 32400,
  13819. 'PYST' => -10800,
  13820. 'PYT' => -14400,
  13821. 'RET' => 14400,
  13822. 'ROTT' => -10800,
  13823. 'SAMST' => 18000,
  13824. 'SAMT' => 14400,
  13825. 'SAST' => 7200,
  13826. 'SBT' => 39600,
  13827. 'SCDT' => 46800,
  13828. 'SCST' => 43200,
  13829. 'SCT' => 14400,
  13830. 'SEST' => 3600,
  13831. 'SGT' => 28800,
  13832. 'SIT' => 28800,
  13833. 'SRT' => -10800,
  13834. 'SST' => -39600,
  13835. 'SYST' => 10800,
  13836. 'SYT' => 7200,
  13837. 'TFT' => 18000,
  13838. 'THAT' => -36000,
  13839. 'TJT' => 18000,
  13840. 'TKT' => -36000,
  13841. 'TMT' => 18000,
  13842. 'TOT' => 46800,
  13843. 'TPT' => 32400,
  13844. 'TRUT' => 36000,
  13845. 'TVT' => 43200,
  13846. 'TWT' => 28800,
  13847. 'UYST' => -7200,
  13848. 'UYT' => -10800,
  13849. 'UZT' => 18000,
  13850. 'VET' => -14400,
  13851. 'VLAST' => 39600,
  13852. 'VLAT' => 36000,
  13853. 'VOST' => 21600,
  13854. 'VUT' => 39600,
  13855. 'WAST' => 7200,
  13856. 'WAT' => 3600,
  13857. 'WDT' => 32400,
  13858. 'WEST' => 3600,
  13859. 'WFT' => 43200,
  13860. 'WIB' => 25200,
  13861. 'WIT' => 32400,
  13862. 'WITA' => 28800,
  13863. 'WKST' => 18000,
  13864. 'WST' => 28800,
  13865. 'YAKST' => 36000,
  13866. 'YAKT' => 32400,
  13867. 'YAPT' => 36000,
  13868. 'YEKST' => 21600,
  13869. 'YEKT' => 18000,
  13870. );
  13871. /**
  13872. * Cached PCRE for SimplePie_Parse_Date::$day
  13873. *
  13874. * @access protected
  13875. * @var string
  13876. */
  13877. var $day_pcre;
  13878. /**
  13879. * Cached PCRE for SimplePie_Parse_Date::$month
  13880. *
  13881. * @access protected
  13882. * @var string
  13883. */
  13884. var $month_pcre;
  13885. /**
  13886. * Array of user-added callback methods
  13887. *
  13888. * @access private
  13889. * @var array
  13890. */
  13891. var $built_in = array();
  13892. /**
  13893. * Array of user-added callback methods
  13894. *
  13895. * @access private
  13896. * @var array
  13897. */
  13898. var $user = array();
  13899. /**
  13900. * Create new SimplePie_Parse_Date object, and set self::day_pcre,
  13901. * self::month_pcre, and self::built_in
  13902. *
  13903. * @access private
  13904. */
  13905. public function __construct()
  13906. {
  13907. $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
  13908. $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
  13909. static $cache;
  13910. if (!isset($cache[get_class($this)]))
  13911. {
  13912. $all_methods = get_class_methods($this);
  13913. foreach ($all_methods as $method)
  13914. {
  13915. if (strtolower(substr($method, 0, 5)) === 'date_')
  13916. {
  13917. $cache[get_class($this)][] = $method;
  13918. }
  13919. }
  13920. }
  13921. foreach ($cache[get_class($this)] as $method)
  13922. {
  13923. $this->built_in[] = $method;
  13924. }
  13925. }
  13926. /**
  13927. * Get the object
  13928. *
  13929. * @access public
  13930. */
  13931. public static function get()
  13932. {
  13933. static $object;
  13934. if (!$object)
  13935. {
  13936. $object = new SimplePie_Parse_Date;
  13937. }
  13938. return $object;
  13939. }
  13940. /**
  13941. * Parse a date
  13942. *
  13943. * @final
  13944. * @access public
  13945. * @param string $date Date to parse
  13946. * @return int Timestamp corresponding to date string, or false on failure
  13947. */
  13948. public function parse($date)
  13949. {
  13950. foreach ($this->user as $method)
  13951. {
  13952. if (($returned = call_user_func($method, $date)) !== false)
  13953. {
  13954. return $returned;
  13955. }
  13956. }
  13957. foreach ($this->built_in as $method)
  13958. {
  13959. if (($returned = call_user_func(array($this, $method), $date)) !== false)
  13960. {
  13961. return $returned;
  13962. }
  13963. }
  13964. return false;
  13965. }
  13966. /**
  13967. * Add a callback method to parse a date
  13968. *
  13969. * @final
  13970. * @access public
  13971. * @param callback $callback
  13972. */
  13973. public function add_callback($callback)
  13974. {
  13975. if (is_callable($callback))
  13976. {
  13977. $this->user[] = $callback;
  13978. }
  13979. else
  13980. {
  13981. trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
  13982. }
  13983. }
  13984. /**
  13985. * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
  13986. * well as allowing any of upper or lower case "T", horizontal tabs, or
  13987. * spaces to be used as the time seperator (including more than one))
  13988. *
  13989. * @access protected
  13990. * @return int Timestamp
  13991. */
  13992. public function date_w3cdtf($date)
  13993. {
  13994. static $pcre;
  13995. if (!$pcre)
  13996. {
  13997. $year = '([0-9]{4})';
  13998. $month = $day = $hour = $minute = $second = '([0-9]{2})';
  13999. $decimal = '([0-9]*)';
  14000. $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
  14001. $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
  14002. }
  14003. if (preg_match($pcre, $date, $match))
  14004. {
  14005. /*
  14006. Capturing subpatterns:
  14007. 1: Year
  14008. 2: Month
  14009. 3: Day
  14010. 4: Hour
  14011. 5: Minute
  14012. 6: Second
  14013. 7: Decimal fraction of a second
  14014. 8: Zulu
  14015. 9: Timezone ±
  14016. 10: Timezone hours
  14017. 11: Timezone minutes
  14018. */
  14019. // Fill in empty matches
  14020. for ($i = count($match); $i <= 3; $i++)
  14021. {
  14022. $match[$i] = '1';
  14023. }
  14024. for ($i = count($match); $i <= 7; $i++)
  14025. {
  14026. $match[$i] = '0';
  14027. }
  14028. // Numeric timezone
  14029. if (isset($match[9]) && $match[9] !== '')
  14030. {
  14031. $timezone = $match[10] * 3600;
  14032. $timezone += $match[11] * 60;
  14033. if ($match[9] === '-')
  14034. {
  14035. $timezone = 0 - $timezone;
  14036. }
  14037. }
  14038. else
  14039. {
  14040. $timezone = 0;
  14041. }
  14042. // Convert the number of seconds to an integer, taking decimals into account
  14043. $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
  14044. return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
  14045. }
  14046. else
  14047. {
  14048. return false;
  14049. }
  14050. }
  14051. /**
  14052. * Remove RFC822 comments
  14053. *
  14054. * @access protected
  14055. * @param string $data Data to strip comments from
  14056. * @return string Comment stripped string
  14057. */
  14058. public function remove_rfc2822_comments($string)
  14059. {
  14060. $string = (string) $string;
  14061. $position = 0;
  14062. $length = strlen($string);
  14063. $depth = 0;
  14064. $output = '';
  14065. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  14066. {
  14067. $output .= substr($string, $position, $pos - $position);
  14068. $position = $pos + 1;
  14069. if ($string[$pos - 1] !== '\\')
  14070. {
  14071. $depth++;
  14072. while ($depth && $position < $length)
  14073. {
  14074. $position += strcspn($string, '()', $position);
  14075. if ($string[$position - 1] === '\\')
  14076. {
  14077. $position++;
  14078. continue;
  14079. }
  14080. elseif (isset($string[$position]))
  14081. {
  14082. switch ($string[$position])
  14083. {
  14084. case '(':
  14085. $depth++;
  14086. break;
  14087. case ')':
  14088. $depth--;
  14089. break;
  14090. }
  14091. $position++;
  14092. }
  14093. else
  14094. {
  14095. break;
  14096. }
  14097. }
  14098. }
  14099. else
  14100. {
  14101. $output .= '(';
  14102. }
  14103. }
  14104. $output .= substr($string, $position);
  14105. return $output;
  14106. }
  14107. /**
  14108. * Parse RFC2822's date format
  14109. *
  14110. * @access protected
  14111. * @return int Timestamp
  14112. */
  14113. public function date_rfc2822($date)
  14114. {
  14115. static $pcre;
  14116. if (!$pcre)
  14117. {
  14118. $wsp = '[\x09\x20]';
  14119. $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
  14120. $optional_fws = $fws . '?';
  14121. $day_name = $this->day_pcre;
  14122. $month = $this->month_pcre;
  14123. $day = '([0-9]{1,2})';
  14124. $hour = $minute = $second = '([0-9]{2})';
  14125. $year = '([0-9]{2,4})';
  14126. $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
  14127. $character_zone = '([A-Z]{1,5})';
  14128. $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
  14129. $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';
  14130. }
  14131. if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
  14132. {
  14133. /*
  14134. Capturing subpatterns:
  14135. 1: Day name
  14136. 2: Day
  14137. 3: Month
  14138. 4: Year
  14139. 5: Hour
  14140. 6: Minute
  14141. 7: Second
  14142. 8: Timezone ±
  14143. 9: Timezone hours
  14144. 10: Timezone minutes
  14145. 11: Alphabetic timezone
  14146. */
  14147. // Find the month number
  14148. $month = $this->month[strtolower($match[3])];
  14149. // Numeric timezone
  14150. if ($match[8] !== '')
  14151. {
  14152. $timezone = $match[9] * 3600;
  14153. $timezone += $match[10] * 60;
  14154. if ($match[8] === '-')
  14155. {
  14156. $timezone = 0 - $timezone;
  14157. }
  14158. }
  14159. // Character timezone
  14160. elseif (isset($this->timezone[strtoupper($match[11])]))
  14161. {
  14162. $timezone = $this->timezone[strtoupper($match[11])];
  14163. }
  14164. // Assume everything else to be -0000
  14165. else
  14166. {
  14167. $timezone = 0;
  14168. }
  14169. // Deal with 2/3 digit years
  14170. if ($match[4] < 50)
  14171. {
  14172. $match[4] += 2000;
  14173. }
  14174. elseif ($match[4] < 1000)
  14175. {
  14176. $match[4] += 1900;
  14177. }
  14178. // Second is optional, if it is empty set it to zero
  14179. if ($match[7] !== '')
  14180. {
  14181. $second = $match[7];
  14182. }
  14183. else
  14184. {
  14185. $second = 0;
  14186. }
  14187. return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
  14188. }
  14189. else
  14190. {
  14191. return false;
  14192. }
  14193. }
  14194. /**
  14195. * Parse RFC850's date format
  14196. *
  14197. * @access protected
  14198. * @return int Timestamp
  14199. */
  14200. public function date_rfc850($date)
  14201. {
  14202. static $pcre;
  14203. if (!$pcre)
  14204. {
  14205. $space = '[\x09\x20]+';
  14206. $day_name = $this->day_pcre;
  14207. $month = $this->month_pcre;
  14208. $day = '([0-9]{1,2})';
  14209. $year = $hour = $minute = $second = '([0-9]{2})';
  14210. $zone = '([A-Z]{1,5})';
  14211. $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
  14212. }
  14213. if (preg_match($pcre, $date, $match))
  14214. {
  14215. /*
  14216. Capturing subpatterns:
  14217. 1: Day name
  14218. 2: Day
  14219. 3: Month
  14220. 4: Year
  14221. 5: Hour
  14222. 6: Minute
  14223. 7: Second
  14224. 8: Timezone
  14225. */
  14226. // Month
  14227. $month = $this->month[strtolower($match[3])];
  14228. // Character timezone
  14229. if (isset($this->timezone[strtoupper($match[8])]))
  14230. {
  14231. $timezone = $this->timezone[strtoupper($match[8])];
  14232. }
  14233. // Assume everything else to be -0000
  14234. else
  14235. {
  14236. $timezone = 0;
  14237. }
  14238. // Deal with 2 digit year
  14239. if ($match[4] < 50)
  14240. {
  14241. $match[4] += 2000;
  14242. }
  14243. else
  14244. {
  14245. $match[4] += 1900;
  14246. }
  14247. return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
  14248. }
  14249. else
  14250. {
  14251. return false;
  14252. }
  14253. }
  14254. /**
  14255. * Parse C99's asctime()'s date format
  14256. *
  14257. * @access protected
  14258. * @return int Timestamp
  14259. */
  14260. public function date_asctime($date)
  14261. {
  14262. static $pcre;
  14263. if (!$pcre)
  14264. {
  14265. $space = '[\x09\x20]+';
  14266. $wday_name = $this->day_pcre;
  14267. $mon_name = $this->month_pcre;
  14268. $day = '([0-9]{1,2})';
  14269. $hour = $sec = $min = '([0-9]{2})';
  14270. $year = '([0-9]{4})';
  14271. $terminator = '\x0A?\x00?';
  14272. $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
  14273. }
  14274. if (preg_match($pcre, $date, $match))
  14275. {
  14276. /*
  14277. Capturing subpatterns:
  14278. 1: Day name
  14279. 2: Month
  14280. 3: Day
  14281. 4: Hour
  14282. 5: Minute
  14283. 6: Second
  14284. 7: Year
  14285. */
  14286. $month = $this->month[strtolower($match[2])];
  14287. return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
  14288. }
  14289. else
  14290. {
  14291. return false;
  14292. }
  14293. }
  14294. /**
  14295. * Parse dates using strtotime()
  14296. *
  14297. * @access protected
  14298. * @return int Timestamp
  14299. */
  14300. public function date_strtotime($date)
  14301. {
  14302. $strtotime = strtotime($date);
  14303. if ($strtotime === -1 || $strtotime === false)
  14304. {
  14305. return false;
  14306. }
  14307. else
  14308. {
  14309. return $strtotime;
  14310. }
  14311. }
  14312. }
  14313. /**
  14314. * Parses XML into something sane
  14315. *
  14316. *
  14317. * This class can be overloaded with {@see SimplePie::set_parser_class()}
  14318. *
  14319. * @package SimplePie
  14320. * @subpackage Parsing
  14321. */
  14322. class SimplePie_Parser
  14323. {
  14324. var $error_code;
  14325. var $error_string;
  14326. var $current_line;
  14327. var $current_column;
  14328. var $current_byte;
  14329. var $separator = ' ';
  14330. var $namespace = array('');
  14331. var $element = array('');
  14332. var $xml_base = array('');
  14333. var $xml_base_explicit = array(false);
  14334. var $xml_lang = array('');
  14335. var $data = array();
  14336. var $datas = array(array());
  14337. var $current_xhtml_construct = -1;
  14338. var $encoding;
  14339. protected $registry;
  14340. public function set_registry(SimplePie_Registry $registry)
  14341. {
  14342. $this->registry = $registry;
  14343. }
  14344. public function parse(&$data, $encoding)
  14345. {
  14346. // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
  14347. if (strtoupper($encoding) === 'US-ASCII')
  14348. {
  14349. $this->encoding = 'UTF-8';
  14350. }
  14351. else
  14352. {
  14353. $this->encoding = $encoding;
  14354. }
  14355. // Strip BOM:
  14356. // UTF-32 Big Endian BOM
  14357. if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
  14358. {
  14359. $data = substr($data, 4);
  14360. }
  14361. // UTF-32 Little Endian BOM
  14362. elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
  14363. {
  14364. $data = substr($data, 4);
  14365. }
  14366. // UTF-16 Big Endian BOM
  14367. elseif (substr($data, 0, 2) === "\xFE\xFF")
  14368. {
  14369. $data = substr($data, 2);
  14370. }
  14371. // UTF-16 Little Endian BOM
  14372. elseif (substr($data, 0, 2) === "\xFF\xFE")
  14373. {
  14374. $data = substr($data, 2);
  14375. }
  14376. // UTF-8 BOM
  14377. elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
  14378. {
  14379. $data = substr($data, 3);
  14380. }
  14381. if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
  14382. {
  14383. $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
  14384. if ($declaration->parse())
  14385. {
  14386. $data = substr($data, $pos + 2);
  14387. $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
  14388. }
  14389. else
  14390. {
  14391. $this->error_string = 'SimplePie bug! Please report this!';
  14392. return false;
  14393. }
  14394. }
  14395. $return = true;
  14396. static $xml_is_sane = null;
  14397. if ($xml_is_sane === null)
  14398. {
  14399. $parser_check = xml_parser_create();
  14400. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  14401. xml_parser_free($parser_check);
  14402. $xml_is_sane = isset($values[0]['value']);
  14403. }
  14404. // Create the parser
  14405. if ($xml_is_sane)
  14406. {
  14407. $xml = xml_parser_create_ns($this->encoding, $this->separator);
  14408. xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
  14409. xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
  14410. xml_set_object($xml, $this);
  14411. xml_set_character_data_handler($xml, 'cdata');
  14412. xml_set_element_handler($xml, 'tag_open', 'tag_close');
  14413. // Parse!
  14414. if (!xml_parse($xml, $data, true))
  14415. {
  14416. $this->error_code = xml_get_error_code($xml);
  14417. $this->error_string = xml_error_string($this->error_code);
  14418. $return = false;
  14419. }
  14420. $this->current_line = xml_get_current_line_number($xml);
  14421. $this->current_column = xml_get_current_column_number($xml);
  14422. $this->current_byte = xml_get_current_byte_index($xml);
  14423. xml_parser_free($xml);
  14424. return $return;
  14425. }
  14426. else
  14427. {
  14428. libxml_clear_errors();
  14429. $xml = new XMLReader();
  14430. $xml->xml($data);
  14431. while (@$xml->read())
  14432. {
  14433. switch ($xml->nodeType)
  14434. {
  14435. case constant('XMLReader::END_ELEMENT'):
  14436. if ($xml->namespaceURI !== '')
  14437. {
  14438. $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
  14439. }
  14440. else
  14441. {
  14442. $tagName = $xml->localName;
  14443. }
  14444. $this->tag_close(null, $tagName);
  14445. break;
  14446. case constant('XMLReader::ELEMENT'):
  14447. $empty = $xml->isEmptyElement;
  14448. if ($xml->namespaceURI !== '')
  14449. {
  14450. $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
  14451. }
  14452. else
  14453. {
  14454. $tagName = $xml->localName;
  14455. }
  14456. $attributes = array();
  14457. while ($xml->moveToNextAttribute())
  14458. {
  14459. if ($xml->namespaceURI !== '')
  14460. {
  14461. $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
  14462. }
  14463. else
  14464. {
  14465. $attrName = $xml->localName;
  14466. }
  14467. $attributes[$attrName] = $xml->value;
  14468. }
  14469. $this->tag_open(null, $tagName, $attributes);
  14470. if ($empty)
  14471. {
  14472. $this->tag_close(null, $tagName);
  14473. }
  14474. break;
  14475. case constant('XMLReader::TEXT'):
  14476. case constant('XMLReader::CDATA'):
  14477. $this->cdata(null, $xml->value);
  14478. break;
  14479. }
  14480. }
  14481. if ($error = libxml_get_last_error())
  14482. {
  14483. $this->error_code = $error->code;
  14484. $this->error_string = $error->message;
  14485. $this->current_line = $error->line;
  14486. $this->current_column = $error->column;
  14487. return false;
  14488. }
  14489. else
  14490. {
  14491. return true;
  14492. }
  14493. }
  14494. }
  14495. public function get_error_code()
  14496. {
  14497. return $this->error_code;
  14498. }
  14499. public function get_error_string()
  14500. {
  14501. return $this->error_string;
  14502. }
  14503. public function get_current_line()
  14504. {
  14505. return $this->current_line;
  14506. }
  14507. public function get_current_column()
  14508. {
  14509. return $this->current_column;
  14510. }
  14511. public function get_current_byte()
  14512. {
  14513. return $this->current_byte;
  14514. }
  14515. public function get_data()
  14516. {
  14517. return $this->data;
  14518. }
  14519. public function tag_open($parser, $tag, $attributes)
  14520. {
  14521. list($this->namespace[], $this->element[]) = $this->split_ns($tag);
  14522. $attribs = array();
  14523. foreach ($attributes as $name => $value)
  14524. {
  14525. list($attrib_namespace, $attribute) = $this->split_ns($name);
  14526. $attribs[$attrib_namespace][$attribute] = $value;
  14527. }
  14528. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
  14529. {
  14530. $this->xml_base[] = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
  14531. $this->xml_base_explicit[] = true;
  14532. }
  14533. else
  14534. {
  14535. $this->xml_base[] = end($this->xml_base);
  14536. $this->xml_base_explicit[] = end($this->xml_base_explicit);
  14537. }
  14538. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
  14539. {
  14540. $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
  14541. }
  14542. else
  14543. {
  14544. $this->xml_lang[] = end($this->xml_lang);
  14545. }
  14546. if ($this->current_xhtml_construct >= 0)
  14547. {
  14548. $this->current_xhtml_construct++;
  14549. if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
  14550. {
  14551. $this->data['data'] .= '<' . end($this->element);
  14552. if (isset($attribs['']))
  14553. {
  14554. foreach ($attribs[''] as $name => $value)
  14555. {
  14556. $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
  14557. }
  14558. }
  14559. $this->data['data'] .= '>';
  14560. }
  14561. }
  14562. else
  14563. {
  14564. $this->datas[] =& $this->data;
  14565. $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
  14566. $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));
  14567. 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')
  14568. || (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')
  14569. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
  14570. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
  14571. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
  14572. {
  14573. $this->current_xhtml_construct = 0;
  14574. }
  14575. }
  14576. }
  14577. public function cdata($parser, $cdata)
  14578. {
  14579. if ($this->current_xhtml_construct >= 0)
  14580. {
  14581. $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
  14582. }
  14583. else
  14584. {
  14585. $this->data['data'] .= $cdata;
  14586. }
  14587. }
  14588. public function tag_close($parser, $tag)
  14589. {
  14590. if ($this->current_xhtml_construct >= 0)
  14591. {
  14592. $this->current_xhtml_construct--;
  14593. 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')))
  14594. {
  14595. $this->data['data'] .= '</' . end($this->element) . '>';
  14596. }
  14597. }
  14598. if ($this->current_xhtml_construct === -1)
  14599. {
  14600. $this->data =& $this->datas[count($this->datas) - 1];
  14601. array_pop($this->datas);
  14602. }
  14603. array_pop($this->element);
  14604. array_pop($this->namespace);
  14605. array_pop($this->xml_base);
  14606. array_pop($this->xml_base_explicit);
  14607. array_pop($this->xml_lang);
  14608. }
  14609. public function split_ns($string)
  14610. {
  14611. static $cache = array();
  14612. if (!isset($cache[$string]))
  14613. {
  14614. if ($pos = strpos($string, $this->separator))
  14615. {
  14616. static $separator_length;
  14617. if (!$separator_length)
  14618. {
  14619. $separator_length = strlen($this->separator);
  14620. }
  14621. $namespace = substr($string, 0, $pos);
  14622. $local_name = substr($string, $pos + $separator_length);
  14623. if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
  14624. {
  14625. $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
  14626. }
  14627. // Normalize the Media RSS namespaces
  14628. if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
  14629. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
  14630. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
  14631. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
  14632. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
  14633. {
  14634. $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
  14635. }
  14636. $cache[$string] = array($namespace, $local_name);
  14637. }
  14638. else
  14639. {
  14640. $cache[$string] = array('', $string);
  14641. }
  14642. }
  14643. return $cache[$string];
  14644. }
  14645. }
  14646. /**
  14647. * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
  14648. *
  14649. * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
  14650. *
  14651. * This class can be overloaded with {@see SimplePie::set_rating_class()}
  14652. *
  14653. * @package SimplePie
  14654. * @subpackage API
  14655. */
  14656. class SimplePie_Rating
  14657. {
  14658. /**
  14659. * Rating scheme
  14660. *
  14661. * @var string
  14662. * @see get_scheme()
  14663. */
  14664. var $scheme;
  14665. /**
  14666. * Rating value
  14667. *
  14668. * @var string
  14669. * @see get_value()
  14670. */
  14671. var $value;
  14672. /**
  14673. * Constructor, used to input the data
  14674. *
  14675. * For documentation on all the parameters, see the corresponding
  14676. * properties and their accessors
  14677. */
  14678. public function __construct($scheme = null, $value = null)
  14679. {
  14680. $this->scheme = $scheme;
  14681. $this->value = $value;
  14682. }
  14683. /**
  14684. * String-ified version
  14685. *
  14686. * @return string
  14687. */
  14688. public function __toString()
  14689. {
  14690. // There is no $this->data here
  14691. return md5(serialize($this));
  14692. }
  14693. /**
  14694. * Get the organizational scheme for the rating
  14695. *
  14696. * @return string|null
  14697. */
  14698. public function get_scheme()
  14699. {
  14700. if ($this->scheme !== null)
  14701. {
  14702. return $this->scheme;
  14703. }
  14704. else
  14705. {
  14706. return null;
  14707. }
  14708. }
  14709. /**
  14710. * Get the value of the rating
  14711. *
  14712. * @return string|null
  14713. */
  14714. public function get_value()
  14715. {
  14716. if ($this->value !== null)
  14717. {
  14718. return $this->value;
  14719. }
  14720. else
  14721. {
  14722. return null;
  14723. }
  14724. }
  14725. }
  14726. /**
  14727. * Handles creating objects and calling methods
  14728. *
  14729. * Access this via {@see SimplePie::get_registry()}
  14730. *
  14731. * @package SimplePie
  14732. */
  14733. class SimplePie_Registry
  14734. {
  14735. /**
  14736. * Default class mapping
  14737. *
  14738. * Overriding classes *must* subclass these.
  14739. *
  14740. * @var array
  14741. */
  14742. protected $default = array(
  14743. 'Cache' => 'SimplePie_Cache',
  14744. 'Locator' => 'SimplePie_Locator',
  14745. 'Parser' => 'SimplePie_Parser',
  14746. 'File' => 'SimplePie_File',
  14747. 'Sanitize' => 'SimplePie_Sanitize',
  14748. 'Item' => 'SimplePie_Item',
  14749. 'Author' => 'SimplePie_Author',
  14750. 'Category' => 'SimplePie_Category',
  14751. 'Enclosure' => 'SimplePie_Enclosure',
  14752. 'Caption' => 'SimplePie_Caption',
  14753. 'Copyright' => 'SimplePie_Copyright',
  14754. 'Credit' => 'SimplePie_Credit',
  14755. 'Rating' => 'SimplePie_Rating',
  14756. 'Restriction' => 'SimplePie_Restriction',
  14757. 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
  14758. 'Source' => 'SimplePie_Source',
  14759. 'Misc' => 'SimplePie_Misc',
  14760. 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
  14761. 'Parse_Date' => 'SimplePie_Parse_Date',
  14762. );
  14763. /**
  14764. * Class mapping
  14765. *
  14766. * @see register()
  14767. * @var array
  14768. */
  14769. protected $classes = array();
  14770. /**
  14771. * Legacy classes
  14772. *
  14773. * @see register()
  14774. * @var array
  14775. */
  14776. protected $legacy = array();
  14777. /**
  14778. * Constructor
  14779. *
  14780. * No-op
  14781. */
  14782. public function __construct() { }
  14783. /**
  14784. * Register a class
  14785. *
  14786. * @param string $type See {@see $default} for names
  14787. * @param string $class Class name, must subclass the corresponding default
  14788. * @param bool $legacy Whether to enable legacy support for this class
  14789. * @return bool Successfulness
  14790. */
  14791. public function register($type, $class, $legacy = false)
  14792. {
  14793. if (!is_subclass_of($class, $this->default[$type]))
  14794. {
  14795. return false;
  14796. }
  14797. $this->classes[$type] = $class;
  14798. if ($legacy)
  14799. {
  14800. $this->legacy[] = $class;
  14801. }
  14802. return true;
  14803. }
  14804. /**
  14805. * Get the class registered for a type
  14806. *
  14807. * Where possible, use {@see create()} or {@see call()} instead
  14808. *
  14809. * @param string $type
  14810. * @return string|null
  14811. */
  14812. public function get_class($type)
  14813. {
  14814. if (!empty($this->classes[$type]))
  14815. {
  14816. return $this->classes[$type];
  14817. }
  14818. if (!empty($this->default[$type]))
  14819. {
  14820. return $this->default[$type];
  14821. }
  14822. return null;
  14823. }
  14824. /**
  14825. * Create a new instance of a given type
  14826. *
  14827. * @param string $type
  14828. * @param array $parameters Parameters to pass to the constructor
  14829. * @return object Instance of class
  14830. */
  14831. public function &create($type, $parameters = array())
  14832. {
  14833. $class = $this->get_class($type);
  14834. if (in_array($class, $this->legacy))
  14835. {
  14836. switch ($type)
  14837. {
  14838. case 'locator':
  14839. // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
  14840. // Specified: file, timeout, useragent, max_checked_feeds
  14841. $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
  14842. array_splice($parameters, 3, 1, $replacement);
  14843. break;
  14844. }
  14845. }
  14846. if (!method_exists($class, '__construct'))
  14847. {
  14848. $instance = new $class;
  14849. }
  14850. else
  14851. {
  14852. $reflector = new ReflectionClass($class);
  14853. $instance = $reflector->newInstanceArgs($parameters);
  14854. }
  14855. if (method_exists($instance, 'set_registry'))
  14856. {
  14857. $instance->set_registry($this);
  14858. }
  14859. return $instance;
  14860. }
  14861. /**
  14862. * Call a static method for a type
  14863. *
  14864. * @param string $type
  14865. * @param string $method
  14866. * @param array $parameters
  14867. * @return mixed
  14868. */
  14869. public function &call($type, $method, $parameters = array())
  14870. {
  14871. $class = $this->get_class($type);
  14872. $result = call_user_func_array(array($class, $method), $parameters);
  14873. return $result;
  14874. }
  14875. }
  14876. /**
  14877. * Handles `<media:restriction>` as defined in Media RSS
  14878. *
  14879. * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
  14880. *
  14881. * This class can be overloaded with {@see SimplePie::set_restriction_class()}
  14882. *
  14883. * @package SimplePie
  14884. * @subpackage API
  14885. */
  14886. class SimplePie_Restriction
  14887. {
  14888. /**
  14889. * Relationship ('allow'/'deny')
  14890. *
  14891. * @var string
  14892. * @see get_relationship()
  14893. */
  14894. var $relationship;
  14895. /**
  14896. * Type of restriction
  14897. *
  14898. * @var string
  14899. * @see get_type()
  14900. */
  14901. var $type;
  14902. /**
  14903. * Restricted values
  14904. *
  14905. * @var string
  14906. * @see get_value()
  14907. */
  14908. var $value;
  14909. /**
  14910. * Constructor, used to input the data
  14911. *
  14912. * For documentation on all the parameters, see the corresponding
  14913. * properties and their accessors
  14914. */
  14915. public function __construct($relationship = null, $type = null, $value = null)
  14916. {
  14917. $this->relationship = $relationship;
  14918. $this->type = $type;
  14919. $this->value = $value;
  14920. }
  14921. /**
  14922. * String-ified version
  14923. *
  14924. * @return string
  14925. */
  14926. public function __toString()
  14927. {
  14928. // There is no $this->data here
  14929. return md5(serialize($this));
  14930. }
  14931. /**
  14932. * Get the relationship
  14933. *
  14934. * @return string|null Either 'allow' or 'deny'
  14935. */
  14936. public function get_relationship()
  14937. {
  14938. if ($this->relationship !== null)
  14939. {
  14940. return $this->relationship;
  14941. }
  14942. else
  14943. {
  14944. return null;
  14945. }
  14946. }
  14947. /**
  14948. * Get the type
  14949. *
  14950. * @return string|null
  14951. */
  14952. public function get_type()
  14953. {
  14954. if ($this->type !== null)
  14955. {
  14956. return $this->type;
  14957. }
  14958. else
  14959. {
  14960. return null;
  14961. }
  14962. }
  14963. /**
  14964. * Get the list of restricted things
  14965. *
  14966. * @return string|null
  14967. */
  14968. public function get_value()
  14969. {
  14970. if ($this->value !== null)
  14971. {
  14972. return $this->value;
  14973. }
  14974. else
  14975. {
  14976. return null;
  14977. }
  14978. }
  14979. }
  14980. /**
  14981. * Used for data cleanup and post-processing
  14982. *
  14983. *
  14984. * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
  14985. *
  14986. * @package SimplePie
  14987. * @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
  14988. */
  14989. class SimplePie_Sanitize
  14990. {
  14991. // Private vars
  14992. var $base;
  14993. // Options
  14994. var $remove_div = true;
  14995. var $image_handler = '';
  14996. var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
  14997. var $encode_instead_of_strip = false;
  14998. var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
  14999. var $strip_comments = false;
  15000. var $output_encoding = 'UTF-8';
  15001. var $enable_cache = true;
  15002. var $cache_location = './cache';
  15003. var $cache_name_function = 'md5';
  15004. var $timeout = 10;
  15005. var $useragent = '';
  15006. var $force_fsockopen = false;
  15007. var $replace_url_attributes = null;
  15008. public function __construct()
  15009. {
  15010. // Set defaults
  15011. $this->set_url_replacements(null);
  15012. }
  15013. public function remove_div($enable = true)
  15014. {
  15015. $this->remove_div = (bool) $enable;
  15016. }
  15017. public function set_image_handler($page = false)
  15018. {
  15019. if ($page)
  15020. {
  15021. $this->image_handler = (string) $page;
  15022. }
  15023. else
  15024. {
  15025. $this->image_handler = false;
  15026. }
  15027. }
  15028. public function set_registry(SimplePie_Registry $registry)
  15029. {
  15030. $this->registry = $registry;
  15031. }
  15032. public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
  15033. {
  15034. if (isset($enable_cache))
  15035. {
  15036. $this->enable_cache = (bool) $enable_cache;
  15037. }
  15038. if ($cache_location)
  15039. {
  15040. $this->cache_location = (string) $cache_location;
  15041. }
  15042. if ($cache_name_function)
  15043. {
  15044. $this->cache_name_function = (string) $cache_name_function;
  15045. }
  15046. }
  15047. public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
  15048. {
  15049. if ($timeout)
  15050. {
  15051. $this->timeout = (string) $timeout;
  15052. }
  15053. if ($useragent)
  15054. {
  15055. $this->useragent = (string) $useragent;
  15056. }
  15057. if ($force_fsockopen)
  15058. {
  15059. $this->force_fsockopen = (string) $force_fsockopen;
  15060. }
  15061. }
  15062. 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'))
  15063. {
  15064. if ($tags)
  15065. {
  15066. if (is_array($tags))
  15067. {
  15068. $this->strip_htmltags = $tags;
  15069. }
  15070. else
  15071. {
  15072. $this->strip_htmltags = explode(',', $tags);
  15073. }
  15074. }
  15075. else
  15076. {
  15077. $this->strip_htmltags = false;
  15078. }
  15079. }
  15080. public function encode_instead_of_strip($encode = false)
  15081. {
  15082. $this->encode_instead_of_strip = (bool) $encode;
  15083. }
  15084. public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
  15085. {
  15086. if ($attribs)
  15087. {
  15088. if (is_array($attribs))
  15089. {
  15090. $this->strip_attributes = $attribs;
  15091. }
  15092. else
  15093. {
  15094. $this->strip_attributes = explode(',', $attribs);
  15095. }
  15096. }
  15097. else
  15098. {
  15099. $this->strip_attributes = false;
  15100. }
  15101. }
  15102. public function strip_comments($strip = false)
  15103. {
  15104. $this->strip_comments = (bool) $strip;
  15105. }
  15106. public function set_output_encoding($encoding = 'UTF-8')
  15107. {
  15108. $this->output_encoding = (string) $encoding;
  15109. }
  15110. /**
  15111. * Set element/attribute key/value pairs of HTML attributes
  15112. * containing URLs that need to be resolved relative to the feed
  15113. *
  15114. * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
  15115. * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
  15116. * |q|@cite
  15117. *
  15118. * @since 1.0
  15119. * @param array|null $element_attribute Element/attribute key/value pairs, null for default
  15120. */
  15121. public function set_url_replacements($element_attribute = null)
  15122. {
  15123. if ($element_attribute === null)
  15124. {
  15125. $element_attribute = array(
  15126. 'a' => 'href',
  15127. 'area' => 'href',
  15128. 'blockquote' => 'cite',
  15129. 'del' => 'cite',
  15130. 'form' => 'action',
  15131. 'img' => array(
  15132. 'longdesc',
  15133. 'src'
  15134. ),
  15135. 'input' => 'src',
  15136. 'ins' => 'cite',
  15137. 'q' => 'cite'
  15138. );
  15139. }
  15140. $this->replace_url_attributes = (array) $element_attribute;
  15141. }
  15142. public function sanitize($data, $type, $base = '')
  15143. {
  15144. $data = trim($data);
  15145. if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
  15146. {
  15147. if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
  15148. {
  15149. 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))
  15150. {
  15151. $type |= SIMPLEPIE_CONSTRUCT_HTML;
  15152. }
  15153. else
  15154. {
  15155. $type |= SIMPLEPIE_CONSTRUCT_TEXT;
  15156. }
  15157. }
  15158. if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
  15159. {
  15160. $data = base64_decode($data);
  15161. }
  15162. if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
  15163. {
  15164. $document = new DOMDocument();
  15165. $document->encoding = 'UTF-8';
  15166. $data = $this->preprocess($data, $type);
  15167. set_error_handler(array('SimplePie_Misc', 'silence_errors'));
  15168. $document->loadHTML($data);
  15169. restore_error_handler();
  15170. // Strip comments
  15171. if ($this->strip_comments)
  15172. {
  15173. $xpath = new DOMXPath($document);
  15174. $comments = $xpath->query('//comment()');
  15175. foreach ($comments as $comment)
  15176. {
  15177. $comment->parentNode->removeChild($comment);
  15178. }
  15179. }
  15180. // Strip out HTML tags and attributes that might cause various security problems.
  15181. // Based on recommendations by Mark Pilgrim at:
  15182. // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
  15183. if ($this->strip_htmltags)
  15184. {
  15185. foreach ($this->strip_htmltags as $tag)
  15186. {
  15187. $this->strip_tag($tag, $document, $type);
  15188. }
  15189. }
  15190. if ($this->strip_attributes)
  15191. {
  15192. foreach ($this->strip_attributes as $attrib)
  15193. {
  15194. $this->strip_attr($attrib, $document);
  15195. }
  15196. }
  15197. // Replace relative URLs
  15198. $this->base = $base;
  15199. foreach ($this->replace_url_attributes as $element => $attributes)
  15200. {
  15201. $this->replace_urls($document, $element, $attributes);
  15202. }
  15203. // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
  15204. if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
  15205. {
  15206. $images = $document->getElementsByTagName('img');
  15207. foreach ($images as $img)
  15208. {
  15209. if ($img->hasAttribute('src'))
  15210. {
  15211. $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
  15212. $cache = $this->registry->call('Cache', 'create', array($this->cache_location, $image_url, 'spi'));
  15213. if ($cache->load())
  15214. {
  15215. $img->setAttribute('src', $this->image_handler . $image_url);
  15216. }
  15217. else
  15218. {
  15219. $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));
  15220. $headers = $file->headers;
  15221. if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
  15222. {
  15223. if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
  15224. {
  15225. $img->setAttribute('src', $this->image_handler . $image_url);
  15226. }
  15227. else
  15228. {
  15229. 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);
  15230. }
  15231. }
  15232. }
  15233. }
  15234. }
  15235. }
  15236. // Remove the DOCTYPE
  15237. // Seems to cause segfaulting if we don't do this
  15238. if ($document->firstChild instanceof DOMDocumentType)
  15239. {
  15240. $document->removeChild($document->firstChild);
  15241. }
  15242. // Move everything from the body to the root
  15243. $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
  15244. $document->replaceChild($real_body, $document->firstChild);
  15245. // Finally, convert to a HTML string
  15246. $data = trim($document->saveHTML());
  15247. if ($this->remove_div)
  15248. {
  15249. $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
  15250. $data = preg_replace('/<\/div>$/', '', $data);
  15251. }
  15252. else
  15253. {
  15254. $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
  15255. }
  15256. }
  15257. if ($type & SIMPLEPIE_CONSTRUCT_IRI)
  15258. {
  15259. $data = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
  15260. }
  15261. if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
  15262. {
  15263. $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
  15264. }
  15265. if ($this->output_encoding !== 'UTF-8')
  15266. {
  15267. $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
  15268. }
  15269. }
  15270. return $data;
  15271. }
  15272. protected function preprocess($html, $type)
  15273. {
  15274. $ret = '';
  15275. if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
  15276. {
  15277. // Atom XHTML constructs are wrapped with a div by default
  15278. // Note: No protection if $html contains a stray </div>!
  15279. $html = '<div>' . $html . '</div>';
  15280. $ret .= '<!DOCTYPE html>';
  15281. $content_type = 'text/html';
  15282. }
  15283. else
  15284. {
  15285. $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
  15286. $content_type = 'application/xhtml+xml';
  15287. }
  15288. $ret .= '<html><head>';
  15289. $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
  15290. $ret .= '</head><body>' . $html . '</body></html>';
  15291. return $ret;
  15292. }
  15293. public function replace_urls($document, $tag, $attributes)
  15294. {
  15295. if (!is_array($attributes))
  15296. {
  15297. $attributes = array($attributes);
  15298. }
  15299. if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
  15300. {
  15301. $elements = $document->getElementsByTagName($tag);
  15302. foreach ($elements as $element)
  15303. {
  15304. foreach ($attributes as $attribute)
  15305. {
  15306. if ($element->hasAttribute($attribute))
  15307. {
  15308. $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
  15309. $element->setAttribute($attribute, $value);
  15310. }
  15311. }
  15312. }
  15313. }
  15314. }
  15315. public function do_strip_htmltags($match)
  15316. {
  15317. if ($this->encode_instead_of_strip)
  15318. {
  15319. if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
  15320. {
  15321. $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
  15322. $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
  15323. return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
  15324. }
  15325. else
  15326. {
  15327. return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
  15328. }
  15329. }
  15330. elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
  15331. {
  15332. return $match[4];
  15333. }
  15334. else
  15335. {
  15336. return '';
  15337. }
  15338. }
  15339. protected function strip_tag($tag, $document, $type)
  15340. {
  15341. $xpath = new DOMXPath($document);
  15342. $elements = $xpath->query('body//' . $tag);
  15343. if ($this->encode_instead_of_strip)
  15344. {
  15345. foreach ($elements as $element)
  15346. {
  15347. $fragment = $document->createDocumentFragment();
  15348. // For elements which aren't script or style, include the tag itself
  15349. if (!in_array($tag, array('script', 'style')))
  15350. {
  15351. $text = '<' . $tag;
  15352. if ($element->hasAttributes())
  15353. {
  15354. $attrs = array();
  15355. foreach ($element->attributes as $name => $attr)
  15356. {
  15357. $value = $attr->value;
  15358. // In XHTML, empty values should never exist, so we repeat the value
  15359. if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
  15360. {
  15361. $value = $name;
  15362. }
  15363. // For HTML, empty is fine
  15364. elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
  15365. {
  15366. $attrs[] = $name;
  15367. continue;
  15368. }
  15369. // Standard attribute text
  15370. $attrs[] = $name . '="' . $attr->value . '"';
  15371. }
  15372. $text .= ' ' . implode(' ', $attrs);
  15373. }
  15374. $text .= '>';
  15375. $fragment->appendChild(new DOMText($text));
  15376. }
  15377. $number = $element->childNodes->length;
  15378. for ($i = $number; $i > 0; $i--)
  15379. {
  15380. $child = $element->childNodes->item(0);
  15381. $fragment->appendChild($child);
  15382. }
  15383. if (!in_array($tag, array('script', 'style')))
  15384. {
  15385. $fragment->appendChild(new DOMText('</' . $tag . '>'));
  15386. }
  15387. $element->parentNode->replaceChild($fragment, $element);
  15388. }
  15389. return;
  15390. }
  15391. elseif (in_array($tag, array('script', 'style')))
  15392. {
  15393. foreach ($elements as $element)
  15394. {
  15395. $element->parentNode->removeChild($element);
  15396. }
  15397. return;
  15398. }
  15399. else
  15400. {
  15401. foreach ($elements as $element)
  15402. {
  15403. $fragment = $document->createDocumentFragment();
  15404. $number = $element->childNodes->length;
  15405. for ($i = $number; $i > 0; $i--)
  15406. {
  15407. $child = $element->childNodes->item(0);
  15408. $fragment->appendChild($child);
  15409. }
  15410. $element->parentNode->replaceChild($fragment, $element);
  15411. }
  15412. }
  15413. }
  15414. protected function strip_attr($attrib, $document)
  15415. {
  15416. $xpath = new DOMXPath($document);
  15417. $elements = $xpath->query('//*[@' . $attrib . ']');
  15418. foreach ($elements as $element)
  15419. {
  15420. $element->removeAttribute($attrib);
  15421. }
  15422. }
  15423. }
  15424. /**
  15425. * Handles `<atom:source>`
  15426. *
  15427. * Used by {@see SimplePie_Item::get_source()}
  15428. *
  15429. * This class can be overloaded with {@see SimplePie::set_source_class()}
  15430. *
  15431. * @package SimplePie
  15432. * @subpackage API
  15433. */
  15434. class SimplePie_Source
  15435. {
  15436. var $item;
  15437. var $data = array();
  15438. protected $registry;
  15439. public function __construct($item, $data)
  15440. {
  15441. $this->item = $item;
  15442. $this->data = $data;
  15443. }
  15444. public function set_registry(SimplePie_Registry $registry)
  15445. {
  15446. $this->registry = $registry;
  15447. }
  15448. public function __toString()
  15449. {
  15450. return md5(serialize($this->data));
  15451. }
  15452. public function get_source_tags($namespace, $tag)
  15453. {
  15454. if (isset($this->data['child'][$namespace][$tag]))
  15455. {
  15456. return $this->data['child'][$namespace][$tag];
  15457. }
  15458. else
  15459. {
  15460. return null;
  15461. }
  15462. }
  15463. public function get_base($element = array())
  15464. {
  15465. return $this->item->get_base($element);
  15466. }
  15467. public function sanitize($data, $type, $base = '')
  15468. {
  15469. return $this->item->sanitize($data, $type, $base);
  15470. }
  15471. public function get_item()
  15472. {
  15473. return $this->item;
  15474. }
  15475. public function get_title()
  15476. {
  15477. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  15478. {
  15479. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  15480. }
  15481. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  15482. {
  15483. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  15484. }
  15485. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  15486. {
  15487. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  15488. }
  15489. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  15490. {
  15491. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  15492. }
  15493. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  15494. {
  15495. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  15496. }
  15497. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  15498. {
  15499. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15500. }
  15501. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  15502. {
  15503. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15504. }
  15505. else
  15506. {
  15507. return null;
  15508. }
  15509. }
  15510. public function get_category($key = 0)
  15511. {
  15512. $categories = $this->get_categories();
  15513. if (isset($categories[$key]))
  15514. {
  15515. return $categories[$key];
  15516. }
  15517. else
  15518. {
  15519. return null;
  15520. }
  15521. }
  15522. public function get_categories()
  15523. {
  15524. $categories = array();
  15525. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  15526. {
  15527. $term = null;
  15528. $scheme = null;
  15529. $label = null;
  15530. if (isset($category['attribs']['']['term']))
  15531. {
  15532. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  15533. }
  15534. if (isset($category['attribs']['']['scheme']))
  15535. {
  15536. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  15537. }
  15538. if (isset($category['attribs']['']['label']))
  15539. {
  15540. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  15541. }
  15542. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  15543. }
  15544. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  15545. {
  15546. // This is really the label, but keep this as the term also for BC.
  15547. // Label will also work on retrieving because that falls back to term.
  15548. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15549. if (isset($category['attribs']['']['domain']))
  15550. {
  15551. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  15552. }
  15553. else
  15554. {
  15555. $scheme = null;
  15556. }
  15557. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  15558. }
  15559. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  15560. {
  15561. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  15562. }
  15563. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  15564. {
  15565. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  15566. }
  15567. if (!empty($categories))
  15568. {
  15569. return array_unique($categories);
  15570. }
  15571. else
  15572. {
  15573. return null;
  15574. }
  15575. }
  15576. public function get_author($key = 0)
  15577. {
  15578. $authors = $this->get_authors();
  15579. if (isset($authors[$key]))
  15580. {
  15581. return $authors[$key];
  15582. }
  15583. else
  15584. {
  15585. return null;
  15586. }
  15587. }
  15588. public function get_authors()
  15589. {
  15590. $authors = array();
  15591. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  15592. {
  15593. $name = null;
  15594. $uri = null;
  15595. $email = null;
  15596. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  15597. {
  15598. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15599. }
  15600. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  15601. {
  15602. $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]));
  15603. }
  15604. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  15605. {
  15606. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15607. }
  15608. if ($name !== null || $email !== null || $uri !== null)
  15609. {
  15610. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  15611. }
  15612. }
  15613. if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  15614. {
  15615. $name = null;
  15616. $url = null;
  15617. $email = null;
  15618. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  15619. {
  15620. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15621. }
  15622. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  15623. {
  15624. $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]));
  15625. }
  15626. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  15627. {
  15628. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15629. }
  15630. if ($name !== null || $email !== null || $url !== null)
  15631. {
  15632. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  15633. }
  15634. }
  15635. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  15636. {
  15637. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  15638. }
  15639. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  15640. {
  15641. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  15642. }
  15643. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  15644. {
  15645. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  15646. }
  15647. if (!empty($authors))
  15648. {
  15649. return array_unique($authors);
  15650. }
  15651. else
  15652. {
  15653. return null;
  15654. }
  15655. }
  15656. public function get_contributor($key = 0)
  15657. {
  15658. $contributors = $this->get_contributors();
  15659. if (isset($contributors[$key]))
  15660. {
  15661. return $contributors[$key];
  15662. }
  15663. else
  15664. {
  15665. return null;
  15666. }
  15667. }
  15668. public function get_contributors()
  15669. {
  15670. $contributors = array();
  15671. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  15672. {
  15673. $name = null;
  15674. $uri = null;
  15675. $email = null;
  15676. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  15677. {
  15678. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15679. }
  15680. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  15681. {
  15682. $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]));
  15683. }
  15684. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  15685. {
  15686. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15687. }
  15688. if ($name !== null || $email !== null || $uri !== null)
  15689. {
  15690. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  15691. }
  15692. }
  15693. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  15694. {
  15695. $name = null;
  15696. $url = null;
  15697. $email = null;
  15698. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  15699. {
  15700. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15701. }
  15702. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  15703. {
  15704. $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]));
  15705. }
  15706. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  15707. {
  15708. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15709. }
  15710. if ($name !== null || $email !== null || $url !== null)
  15711. {
  15712. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  15713. }
  15714. }
  15715. if (!empty($contributors))
  15716. {
  15717. return array_unique($contributors);
  15718. }
  15719. else
  15720. {
  15721. return null;
  15722. }
  15723. }
  15724. public function get_link($key = 0, $rel = 'alternate')
  15725. {
  15726. $links = $this->get_links($rel);
  15727. if (isset($links[$key]))
  15728. {
  15729. return $links[$key];
  15730. }
  15731. else
  15732. {
  15733. return null;
  15734. }
  15735. }
  15736. /**
  15737. * Added for parity between the parent-level and the item/entry-level.
  15738. */
  15739. public function get_permalink()
  15740. {
  15741. return $this->get_link(0);
  15742. }
  15743. public function get_links($rel = 'alternate')
  15744. {
  15745. if (!isset($this->data['links']))
  15746. {
  15747. $this->data['links'] = array();
  15748. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  15749. {
  15750. foreach ($links as $link)
  15751. {
  15752. if (isset($link['attribs']['']['href']))
  15753. {
  15754. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  15755. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  15756. }
  15757. }
  15758. }
  15759. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  15760. {
  15761. foreach ($links as $link)
  15762. {
  15763. if (isset($link['attribs']['']['href']))
  15764. {
  15765. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  15766. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  15767. }
  15768. }
  15769. }
  15770. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  15771. {
  15772. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  15773. }
  15774. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  15775. {
  15776. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  15777. }
  15778. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  15779. {
  15780. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  15781. }
  15782. $keys = array_keys($this->data['links']);
  15783. foreach ($keys as $key)
  15784. {
  15785. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  15786. {
  15787. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  15788. {
  15789. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  15790. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  15791. }
  15792. else
  15793. {
  15794. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  15795. }
  15796. }
  15797. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  15798. {
  15799. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  15800. }
  15801. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  15802. }
  15803. }
  15804. if (isset($this->data['links'][$rel]))
  15805. {
  15806. return $this->data['links'][$rel];
  15807. }
  15808. else
  15809. {
  15810. return null;
  15811. }
  15812. }
  15813. public function get_description()
  15814. {
  15815. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  15816. {
  15817. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  15818. }
  15819. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  15820. {
  15821. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  15822. }
  15823. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  15824. {
  15825. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  15826. }
  15827. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  15828. {
  15829. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  15830. }
  15831. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  15832. {
  15833. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  15834. }
  15835. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  15836. {
  15837. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15838. }
  15839. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  15840. {
  15841. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15842. }
  15843. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  15844. {
  15845. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  15846. }
  15847. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  15848. {
  15849. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  15850. }
  15851. else
  15852. {
  15853. return null;
  15854. }
  15855. }
  15856. public function get_copyright()
  15857. {
  15858. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  15859. {
  15860. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  15861. }
  15862. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  15863. {
  15864. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  15865. }
  15866. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  15867. {
  15868. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15869. }
  15870. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  15871. {
  15872. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15873. }
  15874. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  15875. {
  15876. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15877. }
  15878. else
  15879. {
  15880. return null;
  15881. }
  15882. }
  15883. public function get_language()
  15884. {
  15885. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  15886. {
  15887. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15888. }
  15889. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  15890. {
  15891. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15892. }
  15893. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  15894. {
  15895. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  15896. }
  15897. elseif (isset($this->data['xml_lang']))
  15898. {
  15899. return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  15900. }
  15901. else
  15902. {
  15903. return null;
  15904. }
  15905. }
  15906. public function get_latitude()
  15907. {
  15908. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  15909. {
  15910. return (float) $return[0]['data'];
  15911. }
  15912. 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))
  15913. {
  15914. return (float) $match[1];
  15915. }
  15916. else
  15917. {
  15918. return null;
  15919. }
  15920. }
  15921. public function get_longitude()
  15922. {
  15923. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  15924. {
  15925. return (float) $return[0]['data'];
  15926. }
  15927. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  15928. {
  15929. return (float) $return[0]['data'];
  15930. }
  15931. 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))
  15932. {
  15933. return (float) $match[2];
  15934. }
  15935. else
  15936. {
  15937. return null;
  15938. }
  15939. }
  15940. public function get_image_url()
  15941. {
  15942. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
  15943. {
  15944. return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
  15945. }
  15946. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  15947. {
  15948. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  15949. }
  15950. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  15951. {
  15952. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  15953. }
  15954. else
  15955. {
  15956. return null;
  15957. }
  15958. }
  15959. }
  15960. /**
  15961. * Parses the XML Declaration
  15962. *
  15963. * @package SimplePie
  15964. * @subpackage Parsing
  15965. */
  15966. class SimplePie_XML_Declaration_Parser
  15967. {
  15968. /**
  15969. * XML Version
  15970. *
  15971. * @access public
  15972. * @var string
  15973. */
  15974. var $version = '1.0';
  15975. /**
  15976. * Encoding
  15977. *
  15978. * @access public
  15979. * @var string
  15980. */
  15981. var $encoding = 'UTF-8';
  15982. /**
  15983. * Standalone
  15984. *
  15985. * @access public
  15986. * @var bool
  15987. */
  15988. var $standalone = false;
  15989. /**
  15990. * Current state of the state machine
  15991. *
  15992. * @access private
  15993. * @var string
  15994. */
  15995. var $state = 'before_version_name';
  15996. /**
  15997. * Input data
  15998. *
  15999. * @access private
  16000. * @var string
  16001. */
  16002. var $data = '';
  16003. /**
  16004. * Input data length (to avoid calling strlen() everytime this is needed)
  16005. *
  16006. * @access private
  16007. * @var int
  16008. */
  16009. var $data_length = 0;
  16010. /**
  16011. * Current position of the pointer
  16012. *
  16013. * @var int
  16014. * @access private
  16015. */
  16016. var $position = 0;
  16017. /**
  16018. * Create an instance of the class with the input data
  16019. *
  16020. * @access public
  16021. * @param string $data Input data
  16022. */
  16023. public function __construct($data)
  16024. {
  16025. $this->data = $data;
  16026. $this->data_length = strlen($this->data);
  16027. }
  16028. /**
  16029. * Parse the input data
  16030. *
  16031. * @access public
  16032. * @return bool true on success, false on failure
  16033. */
  16034. public function parse()
  16035. {
  16036. while ($this->state && $this->state !== 'emit' && $this->has_data())
  16037. {
  16038. $state = $this->state;
  16039. $this->$state();
  16040. }
  16041. $this->data = '';
  16042. if ($this->state === 'emit')
  16043. {
  16044. return true;
  16045. }
  16046. else
  16047. {
  16048. $this->version = '';
  16049. $this->encoding = '';
  16050. $this->standalone = '';
  16051. return false;
  16052. }
  16053. }
  16054. /**
  16055. * Check whether there is data beyond the pointer
  16056. *
  16057. * @access private
  16058. * @return bool true if there is further data, false if not
  16059. */
  16060. public function has_data()
  16061. {
  16062. return (bool) ($this->position < $this->data_length);
  16063. }
  16064. /**
  16065. * Advance past any whitespace
  16066. *
  16067. * @return int Number of whitespace characters passed
  16068. */
  16069. public function skip_whitespace()
  16070. {
  16071. $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
  16072. $this->position += $whitespace;
  16073. return $whitespace;
  16074. }
  16075. /**
  16076. * Read value
  16077. */
  16078. public function get_value()
  16079. {
  16080. $quote = substr($this->data, $this->position, 1);
  16081. if ($quote === '"' || $quote === "'")
  16082. {
  16083. $this->position++;
  16084. $len = strcspn($this->data, $quote, $this->position);
  16085. if ($this->has_data())
  16086. {
  16087. $value = substr($this->data, $this->position, $len);
  16088. $this->position += $len + 1;
  16089. return $value;
  16090. }
  16091. }
  16092. return false;
  16093. }
  16094. public function before_version_name()
  16095. {
  16096. if ($this->skip_whitespace())
  16097. {
  16098. $this->state = 'version_name';
  16099. }
  16100. else
  16101. {
  16102. $this->state = false;
  16103. }
  16104. }
  16105. public function version_name()
  16106. {
  16107. if (substr($this->data, $this->position, 7) === 'version')
  16108. {
  16109. $this->position += 7;
  16110. $this->skip_whitespace();
  16111. $this->state = 'version_equals';
  16112. }
  16113. else
  16114. {
  16115. $this->state = false;
  16116. }
  16117. }
  16118. public function version_equals()
  16119. {
  16120. if (substr($this->data, $this->position, 1) === '=')
  16121. {
  16122. $this->position++;
  16123. $this->skip_whitespace();
  16124. $this->state = 'version_value';
  16125. }
  16126. else
  16127. {
  16128. $this->state = false;
  16129. }
  16130. }
  16131. public function version_value()
  16132. {
  16133. if ($this->version = $this->get_value())
  16134. {
  16135. $this->skip_whitespace();
  16136. if ($this->has_data())
  16137. {
  16138. $this->state = 'encoding_name';
  16139. }
  16140. else
  16141. {
  16142. $this->state = 'emit';
  16143. }
  16144. }
  16145. else
  16146. {
  16147. $this->state = false;
  16148. }
  16149. }
  16150. public function encoding_name()
  16151. {
  16152. if (substr($this->data, $this->position, 8) === 'encoding')
  16153. {
  16154. $this->position += 8;
  16155. $this->skip_whitespace();
  16156. $this->state = 'encoding_equals';
  16157. }
  16158. else
  16159. {
  16160. $this->state = 'standalone_name';
  16161. }
  16162. }
  16163. public function encoding_equals()
  16164. {
  16165. if (substr($this->data, $this->position, 1) === '=')
  16166. {
  16167. $this->position++;
  16168. $this->skip_whitespace();
  16169. $this->state = 'encoding_value';
  16170. }
  16171. else
  16172. {
  16173. $this->state = false;
  16174. }
  16175. }
  16176. public function encoding_value()
  16177. {
  16178. if ($this->encoding = $this->get_value())
  16179. {
  16180. $this->skip_whitespace();
  16181. if ($this->has_data())
  16182. {
  16183. $this->state = 'standalone_name';
  16184. }
  16185. else
  16186. {
  16187. $this->state = 'emit';
  16188. }
  16189. }
  16190. else
  16191. {
  16192. $this->state = false;
  16193. }
  16194. }
  16195. public function standalone_name()
  16196. {
  16197. if (substr($this->data, $this->position, 10) === 'standalone')
  16198. {
  16199. $this->position += 10;
  16200. $this->skip_whitespace();
  16201. $this->state = 'standalone_equals';
  16202. }
  16203. else
  16204. {
  16205. $this->state = false;
  16206. }
  16207. }
  16208. public function standalone_equals()
  16209. {
  16210. if (substr($this->data, $this->position, 1) === '=')
  16211. {
  16212. $this->position++;
  16213. $this->skip_whitespace();
  16214. $this->state = 'standalone_value';
  16215. }
  16216. else
  16217. {
  16218. $this->state = false;
  16219. }
  16220. }
  16221. public function standalone_value()
  16222. {
  16223. if ($standalone = $this->get_value())
  16224. {
  16225. switch ($standalone)
  16226. {
  16227. case 'yes':
  16228. $this->standalone = true;
  16229. break;
  16230. case 'no':
  16231. $this->standalone = false;
  16232. break;
  16233. default:
  16234. $this->state = false;
  16235. return;
  16236. }
  16237. $this->skip_whitespace();
  16238. if ($this->has_data())
  16239. {
  16240. $this->state = false;
  16241. }
  16242. else
  16243. {
  16244. $this->state = 'emit';
  16245. }
  16246. }
  16247. else
  16248. {
  16249. $this->state = false;
  16250. }
  16251. }
  16252. }