PageRenderTime 128ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 3ms

/libs/extensions/SimplePie/simplepie.inc

https://gitlab.com/fork/hotarucms
PHP | 17813 lines | 13162 code | 971 blank | 3680 comment | 1277 complexity | 05b0061082aea0dfd9332984c75d6c38 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * SimplePie
  4. *
  5. * A PHP-Based RSS and Atom Feed Framework.
  6. * Takes the hard work out of managing a complete RSS/Atom solution.
  7. *
  8. * Please note: This file is automatically generated by a build script. The
  9. * full original source is always available from http://simplepie.org/
  10. *
  11. * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without modification, are
  15. * permitted provided that the following conditions are met:
  16. *
  17. * * Redistributions of source code must retain the above copyright notice, this list of
  18. * conditions and the following disclaimer.
  19. *
  20. * * Redistributions in binary form must reproduce the above copyright notice, this list
  21. * of conditions and the following disclaimer in the documentation and/or other materials
  22. * provided with the distribution.
  23. *
  24. * * Neither the name of the SimplePie Team nor the names of its contributors may be used
  25. * to endorse or promote products derived from this software without specific prior
  26. * written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  30. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  31. * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  33. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  34. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  35. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * @package SimplePie
  39. * @version 1.4-dev
  40. * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  41. * @author Ryan Parman
  42. * @author Geoffrey Sneddon
  43. * @author Ryan McCue
  44. * @link http://simplepie.org/ SimplePie
  45. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  46. */
  47. /**
  48. * SimplePie Name
  49. */
  50. define('SIMPLEPIE_NAME', 'SimplePie');
  51. /**
  52. * SimplePie Version
  53. */
  54. define('SIMPLEPIE_VERSION', '1.4-dev');
  55. /**
  56. * SimplePie Build
  57. * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
  58. */
  59. define('SIMPLEPIE_BUILD', '20130322141506');
  60. /**
  61. * SimplePie Website URL
  62. */
  63. define('SIMPLEPIE_URL', 'http://simplepie.org');
  64. /**
  65. * SimplePie Useragent
  66. * @see SimplePie::set_useragent()
  67. */
  68. define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
  69. /**
  70. * SimplePie Linkback
  71. */
  72. define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
  73. /**
  74. * No Autodiscovery
  75. * @see SimplePie::set_autodiscovery_level()
  76. */
  77. define('SIMPLEPIE_LOCATOR_NONE', 0);
  78. /**
  79. * Feed Link Element Autodiscovery
  80. * @see SimplePie::set_autodiscovery_level()
  81. */
  82. define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
  83. /**
  84. * Local Feed Extension Autodiscovery
  85. * @see SimplePie::set_autodiscovery_level()
  86. */
  87. define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
  88. /**
  89. * Local Feed Body Autodiscovery
  90. * @see SimplePie::set_autodiscovery_level()
  91. */
  92. define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
  93. /**
  94. * Remote Feed Extension Autodiscovery
  95. * @see SimplePie::set_autodiscovery_level()
  96. */
  97. define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
  98. /**
  99. * Remote Feed Body Autodiscovery
  100. * @see SimplePie::set_autodiscovery_level()
  101. */
  102. define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
  103. /**
  104. * All Feed Autodiscovery
  105. * @see SimplePie::set_autodiscovery_level()
  106. */
  107. define('SIMPLEPIE_LOCATOR_ALL', 31);
  108. /**
  109. * No known feed type
  110. */
  111. define('SIMPLEPIE_TYPE_NONE', 0);
  112. /**
  113. * RSS 0.90
  114. */
  115. define('SIMPLEPIE_TYPE_RSS_090', 1);
  116. /**
  117. * RSS 0.91 (Netscape)
  118. */
  119. define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
  120. /**
  121. * RSS 0.91 (Userland)
  122. */
  123. define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
  124. /**
  125. * RSS 0.91 (both Netscape and Userland)
  126. */
  127. define('SIMPLEPIE_TYPE_RSS_091', 6);
  128. /**
  129. * RSS 0.92
  130. */
  131. define('SIMPLEPIE_TYPE_RSS_092', 8);
  132. /**
  133. * RSS 0.93
  134. */
  135. define('SIMPLEPIE_TYPE_RSS_093', 16);
  136. /**
  137. * RSS 0.94
  138. */
  139. define('SIMPLEPIE_TYPE_RSS_094', 32);
  140. /**
  141. * RSS 1.0
  142. */
  143. define('SIMPLEPIE_TYPE_RSS_10', 64);
  144. /**
  145. * RSS 2.0
  146. */
  147. define('SIMPLEPIE_TYPE_RSS_20', 128);
  148. /**
  149. * RDF-based RSS
  150. */
  151. define('SIMPLEPIE_TYPE_RSS_RDF', 65);
  152. /**
  153. * Non-RDF-based RSS (truly intended as syndication format)
  154. */
  155. define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
  156. /**
  157. * All RSS
  158. */
  159. define('SIMPLEPIE_TYPE_RSS_ALL', 255);
  160. /**
  161. * Atom 0.3
  162. */
  163. define('SIMPLEPIE_TYPE_ATOM_03', 256);
  164. /**
  165. * Atom 1.0
  166. */
  167. define('SIMPLEPIE_TYPE_ATOM_10', 512);
  168. /**
  169. * All Atom
  170. */
  171. define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
  172. /**
  173. * All feed types
  174. */
  175. define('SIMPLEPIE_TYPE_ALL', 1023);
  176. /**
  177. * No construct
  178. */
  179. define('SIMPLEPIE_CONSTRUCT_NONE', 0);
  180. /**
  181. * Text construct
  182. */
  183. define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
  184. /**
  185. * HTML construct
  186. */
  187. define('SIMPLEPIE_CONSTRUCT_HTML', 2);
  188. /**
  189. * XHTML construct
  190. */
  191. define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
  192. /**
  193. * base64-encoded construct
  194. */
  195. define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
  196. /**
  197. * IRI construct
  198. */
  199. define('SIMPLEPIE_CONSTRUCT_IRI', 16);
  200. /**
  201. * A construct that might be HTML
  202. */
  203. define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
  204. /**
  205. * All constructs
  206. */
  207. define('SIMPLEPIE_CONSTRUCT_ALL', 63);
  208. /**
  209. * Don't change case
  210. */
  211. define('SIMPLEPIE_SAME_CASE', 1);
  212. /**
  213. * Change to lowercase
  214. */
  215. define('SIMPLEPIE_LOWERCASE', 2);
  216. /**
  217. * Change to uppercase
  218. */
  219. define('SIMPLEPIE_UPPERCASE', 4);
  220. /**
  221. * PCRE for HTML attributes
  222. */
  223. define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
  224. /**
  225. * PCRE for XML attributes
  226. */
  227. define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
  228. /**
  229. * XML Namespace
  230. */
  231. define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
  232. /**
  233. * Atom 1.0 Namespace
  234. */
  235. define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
  236. /**
  237. * Atom 0.3 Namespace
  238. */
  239. define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
  240. /**
  241. * RDF Namespace
  242. */
  243. define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
  244. /**
  245. * RSS 0.90 Namespace
  246. */
  247. define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
  248. /**
  249. * RSS 1.0 Namespace
  250. */
  251. define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
  252. /**
  253. * RSS 1.0 Content Module Namespace
  254. */
  255. define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
  256. /**
  257. * RSS 2.0 Namespace
  258. * (Stupid, I know, but I'm certain it will confuse people less with support.)
  259. */
  260. define('SIMPLEPIE_NAMESPACE_RSS_20', '');
  261. /**
  262. * DC 1.0 Namespace
  263. */
  264. define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
  265. /**
  266. * DC 1.1 Namespace
  267. */
  268. define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
  269. /**
  270. * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
  271. */
  272. define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
  273. /**
  274. * GeoRSS Namespace
  275. */
  276. define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
  277. /**
  278. * Media RSS Namespace
  279. */
  280. define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
  281. /**
  282. * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
  283. */
  284. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
  285. /**
  286. * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
  287. */
  288. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
  289. /**
  290. * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
  291. */
  292. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
  293. /**
  294. * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
  295. */
  296. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
  297. /**
  298. * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
  299. */
  300. define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
  301. /**
  302. * iTunes RSS Namespace
  303. */
  304. define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
  305. /**
  306. * XHTML Namespace
  307. */
  308. define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
  309. /**
  310. * IANA Link Relations Registry
  311. */
  312. define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
  313. /**
  314. * No file source
  315. */
  316. define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
  317. /**
  318. * Remote file source
  319. */
  320. define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
  321. /**
  322. * Local file source
  323. */
  324. define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
  325. /**
  326. * fsockopen() file source
  327. */
  328. define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
  329. /**
  330. * cURL file source
  331. */
  332. define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
  333. /**
  334. * file_get_contents() file source
  335. */
  336. define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
  337. /**
  338. * SimplePie
  339. *
  340. * @package SimplePie
  341. * @subpackage API
  342. */
  343. class SimplePie
  344. {
  345. /**
  346. * @var array Raw data
  347. * @access private
  348. */
  349. public $data = array();
  350. /**
  351. * @var mixed Error string
  352. * @access private
  353. */
  354. public $error;
  355. /**
  356. * @var object Instance of SimplePie_Sanitize (or other class)
  357. * @see SimplePie::set_sanitize_class()
  358. * @access private
  359. */
  360. public $sanitize;
  361. /**
  362. * @var string SimplePie Useragent
  363. * @see SimplePie::set_useragent()
  364. * @access private
  365. */
  366. public $useragent = SIMPLEPIE_USERAGENT;
  367. /**
  368. * @var string Feed URL
  369. * @see SimplePie::set_feed_url()
  370. * @access private
  371. */
  372. public $feed_url;
  373. /**
  374. * @var object Instance of SimplePie_File to use as a feed
  375. * @see SimplePie::set_file()
  376. * @access private
  377. */
  378. public $file;
  379. /**
  380. * @var string Raw feed data
  381. * @see SimplePie::set_raw_data()
  382. * @access private
  383. */
  384. public $raw_data;
  385. /**
  386. * @var int Timeout for fetching remote files
  387. * @see SimplePie::set_timeout()
  388. * @access private
  389. */
  390. public $timeout = 10;
  391. /**
  392. * @var bool Forces fsockopen() to be used for remote files instead
  393. * of cURL, even if a new enough version is installed
  394. * @see SimplePie::force_fsockopen()
  395. * @access private
  396. */
  397. public $force_fsockopen = false;
  398. /**
  399. * @var bool Force the given data/URL to be treated as a feed no matter what
  400. * it appears like
  401. * @see SimplePie::force_feed()
  402. * @access private
  403. */
  404. public $force_feed = false;
  405. /**
  406. * @var bool Enable/Disable Caching
  407. * @see SimplePie::enable_cache()
  408. * @access private
  409. */
  410. public $cache = true;
  411. /**
  412. * @var int Cache duration (in seconds)
  413. * @see SimplePie::set_cache_duration()
  414. * @access private
  415. */
  416. public $cache_duration = 3600;
  417. /**
  418. * @var int Auto-discovery cache duration (in seconds)
  419. * @see SimplePie::set_autodiscovery_cache_duration()
  420. * @access private
  421. */
  422. public $autodiscovery_cache_duration = 604800; // 7 Days.
  423. /**
  424. * @var string Cache location (relative to executing script)
  425. * @see SimplePie::set_cache_location()
  426. * @access private
  427. */
  428. public $cache_location = './cache';
  429. /**
  430. * @var string Function that creates the cache filename
  431. * @see SimplePie::set_cache_name_function()
  432. * @access private
  433. */
  434. public $cache_name_function = 'md5';
  435. /**
  436. * @var bool Reorder feed by date descending
  437. * @see SimplePie::enable_order_by_date()
  438. * @access private
  439. */
  440. public $order_by_date = true;
  441. /**
  442. * @var mixed Force input encoding to be set to the follow value
  443. * (false, or anything type-cast to false, disables this feature)
  444. * @see SimplePie::set_input_encoding()
  445. * @access private
  446. */
  447. public $input_encoding = false;
  448. /**
  449. * @var int Feed Autodiscovery Level
  450. * @see SimplePie::set_autodiscovery_level()
  451. * @access private
  452. */
  453. public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
  454. /**
  455. * Class registry object
  456. *
  457. * @var SimplePie_Registry
  458. */
  459. public $registry;
  460. /**
  461. * @var int Maximum number of feeds to check with autodiscovery
  462. * @see SimplePie::set_max_checked_feeds()
  463. * @access private
  464. */
  465. public $max_checked_feeds = 10;
  466. /**
  467. * @var array All the feeds found during the autodiscovery process
  468. * @see SimplePie::get_all_discovered_feeds()
  469. * @access private
  470. */
  471. public $all_discovered_feeds = array();
  472. /**
  473. * @var string Web-accessible path to the handler_image.php file.
  474. * @see SimplePie::set_image_handler()
  475. * @access private
  476. */
  477. public $image_handler = '';
  478. /**
  479. * @var array Stores the URLs when multiple feeds are being initialized.
  480. * @see SimplePie::set_feed_url()
  481. * @access private
  482. */
  483. public $multifeed_url = array();
  484. /**
  485. * @var array Stores SimplePie objects when multiple feeds initialized.
  486. * @access private
  487. */
  488. public $multifeed_objects = array();
  489. /**
  490. * @var array Stores the get_object_vars() array for use with multifeeds.
  491. * @see SimplePie::set_feed_url()
  492. * @access private
  493. */
  494. public $config_settings = null;
  495. /**
  496. * @var integer Stores the number of items to return per-feed with multifeeds.
  497. * @see SimplePie::set_item_limit()
  498. * @access private
  499. */
  500. public $item_limit = 0;
  501. /**
  502. * @var array Stores the default attributes to be stripped by strip_attributes().
  503. * @see SimplePie::strip_attributes()
  504. * @access private
  505. */
  506. public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
  507. /**
  508. * @var array Stores the default tags to be stripped by strip_htmltags().
  509. * @see SimplePie::strip_htmltags()
  510. * @access private
  511. */
  512. public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
  513. /**
  514. * The SimplePie class contains feed level data and options
  515. *
  516. * To use SimplePie, create the SimplePie object with no parameters. You can
  517. * then set configuration options using the provided methods. After setting
  518. * them, you must initialise the feed using $feed->init(). At that point the
  519. * object's methods and properties will be available to you.
  520. *
  521. * Previously, it was possible to pass in the feed URL along with cache
  522. * options directly into the constructor. This has been removed as of 1.3 as
  523. * it caused a lot of confusion.
  524. *
  525. * @since 1.0 Preview Release
  526. */
  527. public function __construct()
  528. {
  529. if (version_compare(PHP_VERSION, '5.2', '<'))
  530. {
  531. trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
  532. die();
  533. }
  534. // Other objects, instances created here so we can set options on them
  535. $this->sanitize = new SimplePie_Sanitize();
  536. $this->registry = new SimplePie_Registry();
  537. if (func_num_args() > 0)
  538. {
  539. $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
  540. trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
  541. $args = func_get_args();
  542. switch (count($args)) {
  543. case 3:
  544. $this->set_cache_duration($args[2]);
  545. case 2:
  546. $this->set_cache_location($args[1]);
  547. case 1:
  548. $this->set_feed_url($args[0]);
  549. $this->init();
  550. }
  551. }
  552. }
  553. /**
  554. * Used for converting object to a string
  555. */
  556. public function __toString()
  557. {
  558. return md5(serialize($this->data));
  559. }
  560. /**
  561. * Remove items that link back to this before destroying this object
  562. */
  563. public function __destruct()
  564. {
  565. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  566. {
  567. if (!empty($this->data['items']))
  568. {
  569. foreach ($this->data['items'] as $item)
  570. {
  571. $item->__destruct();
  572. }
  573. unset($item, $this->data['items']);
  574. }
  575. if (!empty($this->data['ordered_items']))
  576. {
  577. foreach ($this->data['ordered_items'] as $item)
  578. {
  579. $item->__destruct();
  580. }
  581. unset($item, $this->data['ordered_items']);
  582. }
  583. }
  584. }
  585. /**
  586. * Force the given data/URL to be treated as a feed
  587. *
  588. * This tells SimplePie to ignore the content-type provided by the server.
  589. * Be careful when using this option, as it will also disable autodiscovery.
  590. *
  591. * @since 1.1
  592. * @param bool $enable Force the given data/URL to be treated as a feed
  593. */
  594. public function force_feed($enable = false)
  595. {
  596. $this->force_feed = (bool) $enable;
  597. }
  598. /**
  599. * Set the URL of the feed you want to parse
  600. *
  601. * This allows you to enter the URL of the feed you want to parse, or the
  602. * website you want to try to use auto-discovery on. This takes priority
  603. * over any set raw data.
  604. *
  605. * You can set multiple feeds to mash together by passing an array instead
  606. * of a string for the $url. Remember that with each additional feed comes
  607. * additional processing and resources.
  608. *
  609. * @since 1.0 Preview Release
  610. * @see set_raw_data()
  611. * @param string|array $url This is the URL (or array of URLs) that you want to parse.
  612. */
  613. public function set_feed_url($url)
  614. {
  615. $this->multifeed_url = array();
  616. if (is_array($url))
  617. {
  618. foreach ($url as $value)
  619. {
  620. $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
  621. }
  622. }
  623. else
  624. {
  625. $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
  626. }
  627. }
  628. /**
  629. * Set an instance of {@see SimplePie_File} to use as a feed
  630. *
  631. * @param SimplePie_File &$file
  632. * @return bool True on success, false on failure
  633. */
  634. public function set_file(&$file)
  635. {
  636. if ($file instanceof SimplePie_File)
  637. {
  638. $this->feed_url = $file->url;
  639. $this->file =& $file;
  640. return true;
  641. }
  642. return false;
  643. }
  644. /**
  645. * Set the raw XML data to parse
  646. *
  647. * Allows you to use a string of RSS/Atom data instead of a remote feed.
  648. *
  649. * If you have a feed available as a string in PHP, you can tell SimplePie
  650. * to parse that data string instead of a remote feed. Any set feed URL
  651. * takes precedence.
  652. *
  653. * @since 1.0 Beta 3
  654. * @param string $data RSS or Atom data as a string.
  655. * @see set_feed_url()
  656. */
  657. public function set_raw_data($data)
  658. {
  659. $this->raw_data = $data;
  660. }
  661. /**
  662. * Set the the default timeout for fetching remote feeds
  663. *
  664. * This allows you to change the maximum time the feed's server to respond
  665. * and send the feed back.
  666. *
  667. * @since 1.0 Beta 3
  668. * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
  669. */
  670. public function set_timeout($timeout = 10)
  671. {
  672. $this->timeout = (int) $timeout;
  673. }
  674. /**
  675. * Force SimplePie to use fsockopen() instead of cURL
  676. *
  677. * @since 1.0 Beta 3
  678. * @param bool $enable Force fsockopen() to be used
  679. */
  680. public function force_fsockopen($enable = false)
  681. {
  682. $this->force_fsockopen = (bool) $enable;
  683. }
  684. /**
  685. * Enable/disable caching in SimplePie.
  686. *
  687. * This option allows you to disable caching all-together in SimplePie.
  688. * However, disabling the cache can lead to longer load times.
  689. *
  690. * @since 1.0 Preview Release
  691. * @param bool $enable Enable caching
  692. */
  693. public function enable_cache($enable = true)
  694. {
  695. $this->cache = (bool) $enable;
  696. }
  697. /**
  698. * Set the length of time (in seconds) that the contents of a feed will be
  699. * cached
  700. *
  701. * @param int $seconds The feed content cache duration
  702. */
  703. public function set_cache_duration($seconds = 3600)
  704. {
  705. $this->cache_duration = (int) $seconds;
  706. }
  707. /**
  708. * Set the length of time (in seconds) that the autodiscovered feed URL will
  709. * be cached
  710. *
  711. * @param int $seconds The autodiscovered feed URL cache duration.
  712. */
  713. public function set_autodiscovery_cache_duration($seconds = 604800)
  714. {
  715. $this->autodiscovery_cache_duration = (int) $seconds;
  716. }
  717. /**
  718. * Set the file system location where the cached files should be stored
  719. *
  720. * @param string $location The file system location.
  721. */
  722. public function set_cache_location($location = './cache')
  723. {
  724. $this->cache_location = (string) $location;
  725. }
  726. /**
  727. * Set whether feed items should be sorted into reverse chronological order
  728. *
  729. * @param bool $enable Sort as reverse chronological order.
  730. */
  731. public function enable_order_by_date($enable = true)
  732. {
  733. $this->order_by_date = (bool) $enable;
  734. }
  735. /**
  736. * Set the character encoding used to parse the feed
  737. *
  738. * This overrides the encoding reported by the feed, however it will fall
  739. * back to the normal encoding detection if the override fails
  740. *
  741. * @param string $encoding Character encoding
  742. */
  743. public function set_input_encoding($encoding = false)
  744. {
  745. if ($encoding)
  746. {
  747. $this->input_encoding = (string) $encoding;
  748. }
  749. else
  750. {
  751. $this->input_encoding = false;
  752. }
  753. }
  754. /**
  755. * Set how much feed autodiscovery to do
  756. *
  757. * @see SIMPLEPIE_LOCATOR_NONE
  758. * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
  759. * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
  760. * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
  761. * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
  762. * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
  763. * @see SIMPLEPIE_LOCATOR_ALL
  764. * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
  765. */
  766. public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
  767. {
  768. $this->autodiscovery = (int) $level;
  769. }
  770. /**
  771. * Get the class registry
  772. *
  773. * Use this to override SimplePie's default classes
  774. * @see SimplePie_Registry
  775. * @return SimplePie_Registry
  776. */
  777. public function &get_registry()
  778. {
  779. return $this->registry;
  780. }
  781. /**#@+
  782. * Useful when you are overloading or extending SimplePie's default classes.
  783. *
  784. * @deprecated Use {@see get_registry()} instead
  785. * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
  786. * @param string $class Name of custom class
  787. * @return boolean True on success, false otherwise
  788. */
  789. /**
  790. * Set which class SimplePie uses for caching
  791. */
  792. public function set_cache_class($class = 'SimplePie_Cache')
  793. {
  794. return $this->registry->register('Cache', $class, true);
  795. }
  796. /**
  797. * Set which class SimplePie uses for auto-discovery
  798. */
  799. public function set_locator_class($class = 'SimplePie_Locator')
  800. {
  801. return $this->registry->register('Locator', $class, true);
  802. }
  803. /**
  804. * Set which class SimplePie uses for XML parsing
  805. */
  806. public function set_parser_class($class = 'SimplePie_Parser')
  807. {
  808. return $this->registry->register('Parser', $class, true);
  809. }
  810. /**
  811. * Set which class SimplePie uses for remote file fetching
  812. */
  813. public function set_file_class($class = 'SimplePie_File')
  814. {
  815. return $this->registry->register('File', $class, true);
  816. }
  817. /**
  818. * Set which class SimplePie uses for data sanitization
  819. */
  820. public function set_sanitize_class($class = 'SimplePie_Sanitize')
  821. {
  822. return $this->registry->register('Sanitize', $class, true);
  823. }
  824. /**
  825. * Set which class SimplePie uses for handling feed items
  826. */
  827. public function set_item_class($class = 'SimplePie_Item')
  828. {
  829. return $this->registry->register('Item', $class, true);
  830. }
  831. /**
  832. * Set which class SimplePie uses for handling author data
  833. */
  834. public function set_author_class($class = 'SimplePie_Author')
  835. {
  836. return $this->registry->register('Author', $class, true);
  837. }
  838. /**
  839. * Set which class SimplePie uses for handling category data
  840. */
  841. public function set_category_class($class = 'SimplePie_Category')
  842. {
  843. return $this->registry->register('Category', $class, true);
  844. }
  845. /**
  846. * Set which class SimplePie uses for feed enclosures
  847. */
  848. public function set_enclosure_class($class = 'SimplePie_Enclosure')
  849. {
  850. return $this->registry->register('Enclosure', $class, true);
  851. }
  852. /**
  853. * Set which class SimplePie uses for `<media:text>` captions
  854. */
  855. public function set_caption_class($class = 'SimplePie_Caption')
  856. {
  857. return $this->registry->register('Caption', $class, true);
  858. }
  859. /**
  860. * Set which class SimplePie uses for `<media:copyright>`
  861. */
  862. public function set_copyright_class($class = 'SimplePie_Copyright')
  863. {
  864. return $this->registry->register('Copyright', $class, true);
  865. }
  866. /**
  867. * Set which class SimplePie uses for `<media:credit>`
  868. */
  869. public function set_credit_class($class = 'SimplePie_Credit')
  870. {
  871. return $this->registry->register('Credit', $class, true);
  872. }
  873. /**
  874. * Set which class SimplePie uses for `<media:rating>`
  875. */
  876. public function set_rating_class($class = 'SimplePie_Rating')
  877. {
  878. return $this->registry->register('Rating', $class, true);
  879. }
  880. /**
  881. * Set which class SimplePie uses for `<media:restriction>`
  882. */
  883. public function set_restriction_class($class = 'SimplePie_Restriction')
  884. {
  885. return $this->registry->register('Restriction', $class, true);
  886. }
  887. /**
  888. * Set which class SimplePie uses for content-type sniffing
  889. */
  890. public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
  891. {
  892. return $this->registry->register('Content_Type_Sniffer', $class, true);
  893. }
  894. /**
  895. * Set which class SimplePie uses item sources
  896. */
  897. public function set_source_class($class = 'SimplePie_Source')
  898. {
  899. return $this->registry->register('Source', $class, true);
  900. }
  901. /**#@-*/
  902. /**
  903. * Set the user agent string
  904. *
  905. * @param string $ua New user agent string.
  906. */
  907. public function set_useragent($ua = SIMPLEPIE_USERAGENT)
  908. {
  909. $this->useragent = (string) $ua;
  910. }
  911. /**
  912. * Set callback function to create cache filename with
  913. *
  914. * @param mixed $function Callback function
  915. */
  916. public function set_cache_name_function($function = 'md5')
  917. {
  918. if (is_callable($function))
  919. {
  920. $this->cache_name_function = $function;
  921. }
  922. }
  923. /**
  924. * Set options to make SP as fast as possible
  925. *
  926. * Forgoes a substantial amount of data sanitization in favor of speed. This
  927. * turns SimplePie into a dumb parser of feeds.
  928. *
  929. * @param bool $set Whether to set them or not
  930. */
  931. public function set_stupidly_fast($set = false)
  932. {
  933. if ($set)
  934. {
  935. $this->enable_order_by_date(false);
  936. $this->remove_div(false);
  937. $this->strip_comments(false);
  938. $this->strip_htmltags(false);
  939. $this->strip_attributes(false);
  940. $this->set_image_handler(false);
  941. }
  942. }
  943. /**
  944. * Set maximum number of feeds to check with autodiscovery
  945. *
  946. * @param int $max Maximum number of feeds to check
  947. */
  948. public function set_max_checked_feeds($max = 10)
  949. {
  950. $this->max_checked_feeds = (int) $max;
  951. }
  952. public function remove_div($enable = true)
  953. {
  954. $this->sanitize->remove_div($enable);
  955. }
  956. public function strip_htmltags($tags = '', $encode = null)
  957. {
  958. if ($tags === '')
  959. {
  960. $tags = $this->strip_htmltags;
  961. }
  962. $this->sanitize->strip_htmltags($tags);
  963. if ($encode !== null)
  964. {
  965. $this->sanitize->encode_instead_of_strip($tags);
  966. }
  967. }
  968. public function encode_instead_of_strip($enable = true)
  969. {
  970. $this->sanitize->encode_instead_of_strip($enable);
  971. }
  972. public function strip_attributes($attribs = '')
  973. {
  974. if ($attribs === '')
  975. {
  976. $attribs = $this->strip_attributes;
  977. }
  978. $this->sanitize->strip_attributes($attribs);
  979. }
  980. /**
  981. * Set the output encoding
  982. *
  983. * Allows you to override SimplePie's output to match that of your webpage.
  984. * This is useful for times when your webpages are not being served as
  985. * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
  986. * is similar to {@see set_input_encoding()}.
  987. *
  988. * It should be noted, however, that not all character encodings can support
  989. * all characters. If your page is being served as ISO-8859-1 and you try
  990. * to display a Japanese feed, you'll likely see garbled characters.
  991. * Because of this, it is highly recommended to ensure that your webpages
  992. * are served as UTF-8.
  993. *
  994. * The number of supported character encodings depends on whether your web
  995. * host supports {@link http://php.net/mbstring mbstring},
  996. * {@link http://php.net/iconv iconv}, or both. See
  997. * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
  998. * more information.
  999. *
  1000. * @param string $encoding
  1001. */
  1002. public function set_output_encoding($encoding = 'UTF-8')
  1003. {
  1004. $this->sanitize->set_output_encoding($encoding);
  1005. }
  1006. public function strip_comments($strip = false)
  1007. {
  1008. $this->sanitize->strip_comments($strip);
  1009. }
  1010. /**
  1011. * Set element/attribute key/value pairs of HTML attributes
  1012. * containing URLs that need to be resolved relative to the feed
  1013. *
  1014. * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
  1015. * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
  1016. * |q|@cite
  1017. *
  1018. * @since 1.0
  1019. * @param array|null $element_attribute Element/attribute key/value pairs, null for default
  1020. */
  1021. public function set_url_replacements($element_attribute = null)
  1022. {
  1023. $this->sanitize->set_url_replacements($element_attribute);
  1024. }
  1025. /**
  1026. * Set the handler to enable the display of cached images.
  1027. *
  1028. * @param str $page Web-accessible path to the handler_image.php file.
  1029. * @param str $qs The query string that the value should be passed to.
  1030. */
  1031. public function set_image_handler($page = false, $qs = 'i')
  1032. {
  1033. if ($page !== false)
  1034. {
  1035. $this->sanitize->set_image_handler($page . '?' . $qs . '=');
  1036. }
  1037. else
  1038. {
  1039. $this->image_handler = '';
  1040. }
  1041. }
  1042. /**
  1043. * Set the limit for items returned per-feed with multifeeds
  1044. *
  1045. * @param integer $limit The maximum number of items to return.
  1046. */
  1047. public function set_item_limit($limit = 0)
  1048. {
  1049. $this->item_limit = (int) $limit;
  1050. }
  1051. /**
  1052. * Enable throwing exceptions
  1053. *
  1054. * @param boolean $enable Should we throw exceptions, or use the old-style error property?
  1055. */
  1056. public function enable_exceptions($enable = true)
  1057. {
  1058. $this->enable_exceptions = $enable;
  1059. }
  1060. /**
  1061. * Initialize the feed object
  1062. *
  1063. * This is what makes everything happen. Period. This is where all of the
  1064. * configuration options get processed, feeds are fetched, cached, and
  1065. * parsed, and all of that other good stuff.
  1066. *
  1067. * @return boolean True if successful, false otherwise
  1068. */
  1069. public function init()
  1070. {
  1071. // Check absolute bare minimum requirements.
  1072. if (!extension_loaded('xml') || !extension_loaded('pcre'))
  1073. {
  1074. return false;
  1075. }
  1076. // 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.
  1077. elseif (!extension_loaded('xmlreader'))
  1078. {
  1079. static $xml_is_sane = null;
  1080. if ($xml_is_sane === null)
  1081. {
  1082. $parser_check = xml_parser_create();
  1083. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  1084. xml_parser_free($parser_check);
  1085. $xml_is_sane = isset($values[0]['value']);
  1086. }
  1087. if (!$xml_is_sane)
  1088. {
  1089. return false;
  1090. }
  1091. }
  1092. if (method_exists($this->sanitize, 'set_registry'))
  1093. {
  1094. $this->sanitize->set_registry($this->registry);
  1095. }
  1096. // Pass whatever was set with config options over to the sanitizer.
  1097. // Pass the classes in for legacy support; new classes should use the registry instead
  1098. $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
  1099. $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
  1100. if (!empty($this->multifeed_url))
  1101. {
  1102. $i = 0;
  1103. $success = 0;
  1104. $this->multifeed_objects = array();
  1105. $this->error = array();
  1106. foreach ($this->multifeed_url as $url)
  1107. {
  1108. $this->multifeed_objects[$i] = clone $this;
  1109. $this->multifeed_objects[$i]->set_feed_url($url);
  1110. $single_success = $this->multifeed_objects[$i]->init();
  1111. $success |= $single_success;
  1112. if (!$single_success)
  1113. {
  1114. $this->error[$i] = $this->multifeed_objects[$i]->error();
  1115. }
  1116. $i++;
  1117. }
  1118. return (bool) $success;
  1119. }
  1120. elseif ($this->feed_url === null && $this->raw_data === null)
  1121. {
  1122. return false;
  1123. }
  1124. $this->error = null;
  1125. $this->data = array();
  1126. $this->multifeed_objects = array();
  1127. $cache = false;
  1128. if ($this->feed_url !== null)
  1129. {
  1130. $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
  1131. // Decide whether to enable caching
  1132. if ($this->cache && $parsed_feed_url['scheme'] !== '')
  1133. {
  1134. $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
  1135. }
  1136. // Fetch the data via SimplePie_File into $this->raw_data
  1137. if (($fetched = $this->fetch_data($cache)) === true)
  1138. {
  1139. return true;
  1140. }
  1141. elseif ($fetched === false) {
  1142. return false;
  1143. }
  1144. list($headers, $sniffed) = $fetched;
  1145. }
  1146. // Set up array of possible encodings
  1147. $encodings = array();
  1148. // First check to see if input has been overridden.
  1149. if ($this->input_encoding !== false)
  1150. {
  1151. $encodings[] = $this->input_encoding;
  1152. }
  1153. $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
  1154. $text_types = array('text/xml', 'text/xml-external-parsed-entity');
  1155. // RFC 3023 (only applies to sniffed content)
  1156. if (isset($sniffed))
  1157. {
  1158. if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
  1159. {
  1160. if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
  1161. {
  1162. $encodings[] = strtoupper($charset[1]);
  1163. }
  1164. $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
  1165. $encodings[] = 'UTF-8';
  1166. }
  1167. elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
  1168. {
  1169. if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
  1170. {
  1171. $encodings[] = $charset[1];
  1172. }
  1173. $encodings[] = 'US-ASCII';
  1174. }
  1175. // Text MIME-type default
  1176. elseif (substr($sniffed, 0, 5) === 'text/')
  1177. {
  1178. $encodings[] = 'US-ASCII';
  1179. }
  1180. }
  1181. // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
  1182. $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
  1183. $encodings[] = 'UTF-8';
  1184. $encodings[] = 'ISO-8859-1';
  1185. // There's no point in trying an encoding twice
  1186. $encodings = array_unique($encodings);
  1187. // Loop through each possible encoding, till we return something, or run out of possibilities
  1188. foreach ($encodings as $encoding)
  1189. {
  1190. // Change the encoding to UTF-8 (as we always use UTF-8 internally)
  1191. if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
  1192. {
  1193. // Create new parser
  1194. $parser = $this->registry->create('Parser');
  1195. // If it's parsed fine
  1196. if ($parser->parse($utf8_data, 'UTF-8'))
  1197. {
  1198. $this->data = $parser->get_data();
  1199. if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
  1200. {
  1201. $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
  1202. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1203. return false;
  1204. }
  1205. if (isset($headers))
  1206. {
  1207. $this->data['headers'] = $headers;
  1208. }
  1209. $this->data['build'] = SIMPLEPIE_BUILD;
  1210. // Cache the file if caching is enabled
  1211. if ($cache && !$cache->save($this))
  1212. {
  1213. 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);
  1214. }
  1215. return true;
  1216. }
  1217. }
  1218. }
  1219. if (isset($parser))
  1220. {
  1221. // We have an error, just set SimplePie_Misc::error to it and quit
  1222. $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());
  1223. }
  1224. else
  1225. {
  1226. $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.';
  1227. }
  1228. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1229. return false;
  1230. }
  1231. /**
  1232. * Fetch the data via SimplePie_File
  1233. *
  1234. * If the data is already cached, attempt to fetch it from there instead
  1235. * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
  1236. * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
  1237. */
  1238. protected function fetch_data(&$cache)
  1239. {
  1240. // If it's enabled, use the cache
  1241. if ($cache)
  1242. {
  1243. // Load the Cache
  1244. $this->data = $cache->load();
  1245. if (!empty($this->data))
  1246. {
  1247. // If the cache is for an outdated build of SimplePie
  1248. if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
  1249. {
  1250. $cache->unlink();
  1251. $this->data = array();
  1252. }
  1253. // If we've hit a collision just rerun it with caching disabled
  1254. elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
  1255. {
  1256. $cache = false;
  1257. $this->data = array();
  1258. }
  1259. // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
  1260. elseif (isset($this->data['feed_url']))
  1261. {
  1262. // If the autodiscovery cache is still valid use it.
  1263. if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
  1264. {
  1265. // Do not need to do feed autodiscovery yet.
  1266. if ($this->data['feed_url'] !== $this->data['url'])
  1267. {
  1268. $this->set_feed_url($this->data['feed_url']);
  1269. return $this->init();
  1270. }
  1271. $cache->unlink();
  1272. $this->data = array();
  1273. }
  1274. }
  1275. // Check if the cache has been updated
  1276. elseif ($cache->mtime() + $this->cache_duration < time())
  1277. {
  1278. // If we have last-modified and/or etag set
  1279. if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
  1280. {
  1281. $headers = array(
  1282. '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',
  1283. );
  1284. if (isset($this->data['headers']['last-modified']))
  1285. {
  1286. $headers['if-modified-since'] = $this->data['headers']['last-modified'];
  1287. }
  1288. if (isset($this->data['headers']['etag']))
  1289. {
  1290. $headers['if-none-match'] = $this->data['headers']['etag'];
  1291. }
  1292. $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
  1293. if ($file->success)
  1294. {
  1295. if ($file->status_code === 304)
  1296. {
  1297. $cache->touch();
  1298. return true;
  1299. }
  1300. }
  1301. else
  1302. {
  1303. unset($file);
  1304. }
  1305. }
  1306. }
  1307. // If the cache is still valid, just return true
  1308. else
  1309. {
  1310. $this->raw_data = false;
  1311. return true;
  1312. }
  1313. }
  1314. // If the cache is empty, delete it
  1315. else
  1316. {
  1317. $cache->unlink();
  1318. $this->data = array();
  1319. }
  1320. }
  1321. // 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.
  1322. if (!isset($file))
  1323. {
  1324. if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
  1325. {
  1326. $file =& $this->file;
  1327. }
  1328. else
  1329. {
  1330. $headers = array(
  1331. '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',
  1332. );
  1333. $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
  1334. }
  1335. }
  1336. // If the file connection has an error, set SimplePie::error to that and quit
  1337. if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
  1338. {
  1339. $this->error = $file->error;
  1340. return !empty($this->data);
  1341. }
  1342. if (!$this->force_feed)
  1343. {
  1344. // Check if the supplied URL is a feed, if it isn't, look for it.
  1345. $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
  1346. if (!$locate->is_feed($file))
  1347. {
  1348. // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
  1349. unset($file);
  1350. try
  1351. {
  1352. if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
  1353. {
  1354. $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.";
  1355. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
  1356. return false;
  1357. }
  1358. }
  1359. catch (SimplePie_Exception $e)
  1360. {
  1361. // This is usually because DOMDocument doesn't exist
  1362. $this->error = $e->getMessage();
  1363. $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
  1364. return false;
  1365. }
  1366. if ($cache)
  1367. {
  1368. $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
  1369. if (!$cache->save($this))
  1370. {
  1371. 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);
  1372. }
  1373. $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
  1374. }
  1375. $this->feed_url = $file->url;
  1376. }
  1377. $locate = null;
  1378. }
  1379. $this->raw_data = $file->body;
  1380. $headers = $file->headers;
  1381. $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
  1382. $sniffed = $sniffer->get_type();
  1383. return array($headers, $sniffed);
  1384. }
  1385. /**
  1386. * Get the error message for the occured error
  1387. *
  1388. * @return string|array Error message, or array of messages for multifeeds
  1389. */
  1390. public function error()
  1391. {
  1392. return $this->error;
  1393. }
  1394. /**
  1395. * Get the raw XML
  1396. *
  1397. * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
  1398. * the data instead of printing it.
  1399. *
  1400. * @return string|boolean Raw XML data, false if the cache is used
  1401. */
  1402. public function get_raw_data()
  1403. {
  1404. return $this->raw_data;
  1405. }
  1406. /**
  1407. * Get the character encoding used for output
  1408. *
  1409. * @since Preview Release
  1410. * @return string
  1411. */
  1412. public function get_encoding()
  1413. {
  1414. return $this->sanitize->output_encoding;
  1415. }
  1416. /**
  1417. * Send the content-type header with correct encoding
  1418. *
  1419. * This method ensures that the SimplePie-enabled page is being served with
  1420. * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
  1421. * and character encoding HTTP headers (character encoding determined by the
  1422. * {@see set_output_encoding} config option).
  1423. *
  1424. * This won't work properly if any content or whitespace has already been
  1425. * sent to the browser, because it relies on PHP's
  1426. * {@link http://php.net/header header()} function, and these are the
  1427. * circumstances under which the function works.
  1428. *
  1429. * Because it's setting these settings for the entire page (as is the nature
  1430. * of HTTP headers), this should only be used once per page (again, at the
  1431. * top).
  1432. *
  1433. * @param string $mime MIME type to serve the page as
  1434. */
  1435. public function handle_content_type($mime = 'text/html')
  1436. {
  1437. if (!headers_sent())
  1438. {
  1439. $header = "Content-type: $mime;";
  1440. if ($this->get_encoding())
  1441. {
  1442. $header .= ' charset=' . $this->get_encoding();
  1443. }
  1444. else
  1445. {
  1446. $header .= ' charset=UTF-8';
  1447. }
  1448. header($header);
  1449. }
  1450. }
  1451. /**
  1452. * Get the type of the feed
  1453. *
  1454. * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
  1455. * using {@link http://php.net/language.operators.bitwise bitwise operators}
  1456. *
  1457. * @since 0.8 (usage changed to using constants in 1.0)
  1458. * @see SIMPLEPIE_TYPE_NONE Unknown.
  1459. * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
  1460. * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
  1461. * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
  1462. * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
  1463. * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
  1464. * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
  1465. * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
  1466. * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
  1467. * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
  1468. * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
  1469. * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
  1470. * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
  1471. * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
  1472. * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
  1473. * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
  1474. * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
  1475. * @return int SIMPLEPIE_TYPE_* constant
  1476. */
  1477. public function get_type()
  1478. {
  1479. if (!isset($this->data['type']))
  1480. {
  1481. $this->data['type'] = SIMPLEPIE_TYPE_ALL;
  1482. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
  1483. {
  1484. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
  1485. }
  1486. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
  1487. {
  1488. $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
  1489. }
  1490. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
  1491. {
  1492. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
  1493. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
  1494. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
  1495. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
  1496. {
  1497. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
  1498. }
  1499. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
  1500. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
  1501. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
  1502. || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
  1503. {
  1504. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
  1505. }
  1506. }
  1507. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
  1508. {
  1509. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
  1510. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  1511. {
  1512. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
  1513. {
  1514. case '0.91':
  1515. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
  1516. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  1517. {
  1518. switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
  1519. {
  1520. case '0':
  1521. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
  1522. break;
  1523. case '24':
  1524. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
  1525. break;
  1526. }
  1527. }
  1528. break;
  1529. case '0.92':
  1530. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
  1531. break;
  1532. case '0.93':
  1533. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
  1534. break;
  1535. case '0.94':
  1536. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
  1537. break;
  1538. case '2.0':
  1539. $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
  1540. break;
  1541. }
  1542. }
  1543. }
  1544. else
  1545. {
  1546. $this->data['type'] = SIMPLEPIE_TYPE_NONE;
  1547. }
  1548. }
  1549. return $this->data['type'];
  1550. }
  1551. /**
  1552. * Get the URL for the feed
  1553. *
  1554. * May or may not be different from the URL passed to {@see set_feed_url()},
  1555. * depending on whether auto-discovery was used.
  1556. *
  1557. * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
  1558. * @todo If we have a perm redirect we should return the new URL
  1559. * @todo When we make the above change, let's support <itunes:new-feed-url> as well
  1560. * @todo Also, |atom:link|@rel=self
  1561. * @return string|null
  1562. */
  1563. public function subscribe_url()
  1564. {
  1565. if ($this->feed_url !== null)
  1566. {
  1567. return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
  1568. }
  1569. else
  1570. {
  1571. return null;
  1572. }
  1573. }
  1574. /**
  1575. * Get data for an feed-level element
  1576. *
  1577. * This method allows you to get access to ANY element/attribute that is a
  1578. * sub-element of the opening feed tag.
  1579. *
  1580. * The return value is an indexed array of elements matching the given
  1581. * namespace and tag name. Each element has `attribs`, `data` and `child`
  1582. * subkeys. For `attribs` and `child`, these contain namespace subkeys.
  1583. * `attribs` then has one level of associative name => value data (where
  1584. * `value` is a string) after the namespace. `child` has tag-indexed keys
  1585. * after the namespace, each member of which is an indexed array matching
  1586. * this same format.
  1587. *
  1588. * For example:
  1589. * <pre>
  1590. * // This is probably a bad example because we already support
  1591. * // <media:content> natively, but it shows you how to parse through
  1592. * // the nodes.
  1593. * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
  1594. * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
  1595. * $file = $content[0]['attribs']['']['url'];
  1596. * echo $file;
  1597. * </pre>
  1598. *
  1599. * @since 1.0
  1600. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1601. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1602. * @param string $tag Tag name
  1603. * @return array
  1604. */
  1605. public function get_feed_tags($namespace, $tag)
  1606. {
  1607. $type = $this->get_type();
  1608. if ($type & SIMPLEPIE_TYPE_ATOM_10)
  1609. {
  1610. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
  1611. {
  1612. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
  1613. }
  1614. }
  1615. if ($type & SIMPLEPIE_TYPE_ATOM_03)
  1616. {
  1617. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
  1618. {
  1619. return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
  1620. }
  1621. }
  1622. if ($type & SIMPLEPIE_TYPE_RSS_RDF)
  1623. {
  1624. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
  1625. {
  1626. return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
  1627. }
  1628. }
  1629. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1630. {
  1631. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
  1632. {
  1633. return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
  1634. }
  1635. }
  1636. return null;
  1637. }
  1638. /**
  1639. * Get data for an channel-level element
  1640. *
  1641. * This method allows you to get access to ANY element/attribute in the
  1642. * channel/header section of the feed.
  1643. *
  1644. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  1645. *
  1646. * @since 1.0
  1647. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1648. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1649. * @param string $tag Tag name
  1650. * @return array
  1651. */
  1652. public function get_channel_tags($namespace, $tag)
  1653. {
  1654. $type = $this->get_type();
  1655. if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
  1656. {
  1657. if ($return = $this->get_feed_tags($namespace, $tag))
  1658. {
  1659. return $return;
  1660. }
  1661. }
  1662. if ($type & SIMPLEPIE_TYPE_RSS_10)
  1663. {
  1664. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
  1665. {
  1666. if (isset($channel[0]['child'][$namespace][$tag]))
  1667. {
  1668. return $channel[0]['child'][$namespace][$tag];
  1669. }
  1670. }
  1671. }
  1672. if ($type & SIMPLEPIE_TYPE_RSS_090)
  1673. {
  1674. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
  1675. {
  1676. if (isset($channel[0]['child'][$namespace][$tag]))
  1677. {
  1678. return $channel[0]['child'][$namespace][$tag];
  1679. }
  1680. }
  1681. }
  1682. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1683. {
  1684. if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
  1685. {
  1686. if (isset($channel[0]['child'][$namespace][$tag]))
  1687. {
  1688. return $channel[0]['child'][$namespace][$tag];
  1689. }
  1690. }
  1691. }
  1692. return null;
  1693. }
  1694. /**
  1695. * Get data for an channel-level element
  1696. *
  1697. * This method allows you to get access to ANY element/attribute in the
  1698. * image/logo section of the feed.
  1699. *
  1700. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  1701. *
  1702. * @since 1.0
  1703. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  1704. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  1705. * @param string $tag Tag name
  1706. * @return array
  1707. */
  1708. public function get_image_tags($namespace, $tag)
  1709. {
  1710. $type = $this->get_type();
  1711. if ($type & SIMPLEPIE_TYPE_RSS_10)
  1712. {
  1713. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
  1714. {
  1715. if (isset($image[0]['child'][$namespace][$tag]))
  1716. {
  1717. return $image[0]['child'][$namespace][$tag];
  1718. }
  1719. }
  1720. }
  1721. if ($type & SIMPLEPIE_TYPE_RSS_090)
  1722. {
  1723. if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
  1724. {
  1725. if (isset($image[0]['child'][$namespace][$tag]))
  1726. {
  1727. return $image[0]['child'][$namespace][$tag];
  1728. }
  1729. }
  1730. }
  1731. if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
  1732. {
  1733. if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
  1734. {
  1735. if (isset($image[0]['child'][$namespace][$tag]))
  1736. {
  1737. return $image[0]['child'][$namespace][$tag];
  1738. }
  1739. }
  1740. }
  1741. return null;
  1742. }
  1743. /**
  1744. * Get the base URL value from the feed
  1745. *
  1746. * Uses `<xml:base>` if available, otherwise uses the first link in the
  1747. * feed, or failing that, the URL of the feed itself.
  1748. *
  1749. * @see get_link
  1750. * @see subscribe_url
  1751. *
  1752. * @param array $element
  1753. * @return string
  1754. */
  1755. public function get_base($element = array())
  1756. {
  1757. if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
  1758. {
  1759. return $element['xml_base'];
  1760. }
  1761. elseif ($this->get_link() !== null)
  1762. {
  1763. return $this->get_link();
  1764. }
  1765. else
  1766. {
  1767. return $this->subscribe_url();
  1768. }
  1769. }
  1770. /**
  1771. * Sanitize feed data
  1772. *
  1773. * @access private
  1774. * @see SimplePie_Sanitize::sanitize()
  1775. * @param string $data Data to sanitize
  1776. * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
  1777. * @param string $base Base URL to resolve URLs against
  1778. * @return string Sanitized data
  1779. */
  1780. public function sanitize($data, $type, $base = '')
  1781. {
  1782. try
  1783. {
  1784. return $this->sanitize->sanitize($data, $type, $base);
  1785. }
  1786. catch (SimplePie_Exception $e)
  1787. {
  1788. if (!$this->enable_exceptions)
  1789. {
  1790. $this->error = $e->getMessage();
  1791. $this->registry->call('Misc', 'error', array($this->error, E_USER_WARNING, $e->getFile(), $e->getLine()));
  1792. return '';
  1793. }
  1794. throw $e;
  1795. }
  1796. }
  1797. /**
  1798. * Get the title of the feed
  1799. *
  1800. * Uses `<atom:title>`, `<title>` or `<dc:title>`
  1801. *
  1802. * @since 1.0 (previously called `get_feed_title` since 0.8)
  1803. * @return string|null
  1804. */
  1805. public function get_title()
  1806. {
  1807. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  1808. {
  1809. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  1810. }
  1811. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  1812. {
  1813. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  1814. }
  1815. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  1816. {
  1817. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1818. }
  1819. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  1820. {
  1821. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1822. }
  1823. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  1824. {
  1825. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  1826. }
  1827. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  1828. {
  1829. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1830. }
  1831. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  1832. {
  1833. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1834. }
  1835. else
  1836. {
  1837. return null;
  1838. }
  1839. }
  1840. /**
  1841. * Get a category for the feed
  1842. *
  1843. * @since Unknown
  1844. * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
  1845. * @return SimplePie_Category|null
  1846. */
  1847. public function get_category($key = 0)
  1848. {
  1849. $categories = $this->get_categories();
  1850. if (isset($categories[$key]))
  1851. {
  1852. return $categories[$key];
  1853. }
  1854. else
  1855. {
  1856. return null;
  1857. }
  1858. }
  1859. /**
  1860. * Get all categories for the feed
  1861. *
  1862. * Uses `<atom:category>`, `<category>` or `<dc:subject>`
  1863. *
  1864. * @since Unknown
  1865. * @return array|null List of {@see SimplePie_Category} objects
  1866. */
  1867. public function get_categories()
  1868. {
  1869. $categories = array();
  1870. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  1871. {
  1872. $term = null;
  1873. $scheme = null;
  1874. $label = null;
  1875. if (isset($category['attribs']['']['term']))
  1876. {
  1877. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  1878. }
  1879. if (isset($category['attribs']['']['scheme']))
  1880. {
  1881. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  1882. }
  1883. if (isset($category['attribs']['']['label']))
  1884. {
  1885. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  1886. }
  1887. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  1888. }
  1889. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  1890. {
  1891. // This is really the label, but keep this as the term also for BC.
  1892. // Label will also work on retrieving because that falls back to term.
  1893. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1894. if (isset($category['attribs']['']['domain']))
  1895. {
  1896. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  1897. }
  1898. else
  1899. {
  1900. $scheme = null;
  1901. }
  1902. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  1903. }
  1904. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  1905. {
  1906. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1907. }
  1908. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  1909. {
  1910. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1911. }
  1912. if (!empty($categories))
  1913. {
  1914. return array_unique($categories);
  1915. }
  1916. else
  1917. {
  1918. return null;
  1919. }
  1920. }
  1921. /**
  1922. * Get an author for the feed
  1923. *
  1924. * @since 1.1
  1925. * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
  1926. * @return SimplePie_Author|null
  1927. */
  1928. public function get_author($key = 0)
  1929. {
  1930. $authors = $this->get_authors();
  1931. if (isset($authors[$key]))
  1932. {
  1933. return $authors[$key];
  1934. }
  1935. else
  1936. {
  1937. return null;
  1938. }
  1939. }
  1940. /**
  1941. * Get all authors for the feed
  1942. *
  1943. * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
  1944. *
  1945. * @since 1.1
  1946. * @return array|null List of {@see SimplePie_Author} objects
  1947. */
  1948. public function get_authors()
  1949. {
  1950. $authors = array();
  1951. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  1952. {
  1953. $name = null;
  1954. $uri = null;
  1955. $email = null;
  1956. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  1957. {
  1958. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1959. }
  1960. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  1961. {
  1962. $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]));
  1963. }
  1964. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  1965. {
  1966. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1967. }
  1968. if ($name !== null || $email !== null || $uri !== null)
  1969. {
  1970. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  1971. }
  1972. }
  1973. if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  1974. {
  1975. $name = null;
  1976. $url = null;
  1977. $email = null;
  1978. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  1979. {
  1980. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1981. }
  1982. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  1983. {
  1984. $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]));
  1985. }
  1986. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  1987. {
  1988. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  1989. }
  1990. if ($name !== null || $email !== null || $url !== null)
  1991. {
  1992. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  1993. }
  1994. }
  1995. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  1996. {
  1997. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  1998. }
  1999. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  2000. {
  2001. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  2002. }
  2003. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  2004. {
  2005. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  2006. }
  2007. if (!empty($authors))
  2008. {
  2009. return array_unique($authors);
  2010. }
  2011. else
  2012. {
  2013. return null;
  2014. }
  2015. }
  2016. /**
  2017. * Get a contributor for the feed
  2018. *
  2019. * @since 1.1
  2020. * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
  2021. * @return SimplePie_Author|null
  2022. */
  2023. public function get_contributor($key = 0)
  2024. {
  2025. $contributors = $this->get_contributors();
  2026. if (isset($contributors[$key]))
  2027. {
  2028. return $contributors[$key];
  2029. }
  2030. else
  2031. {
  2032. return null;
  2033. }
  2034. }
  2035. /**
  2036. * Get all contributors for the feed
  2037. *
  2038. * Uses `<atom:contributor>`
  2039. *
  2040. * @since 1.1
  2041. * @return array|null List of {@see SimplePie_Author} objects
  2042. */
  2043. public function get_contributors()
  2044. {
  2045. $contributors = array();
  2046. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  2047. {
  2048. $name = null;
  2049. $uri = null;
  2050. $email = null;
  2051. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  2052. {
  2053. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2054. }
  2055. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  2056. {
  2057. $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]));
  2058. }
  2059. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  2060. {
  2061. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2062. }
  2063. if ($name !== null || $email !== null || $uri !== null)
  2064. {
  2065. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  2066. }
  2067. }
  2068. foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  2069. {
  2070. $name = null;
  2071. $url = null;
  2072. $email = null;
  2073. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  2074. {
  2075. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2076. }
  2077. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  2078. {
  2079. $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]));
  2080. }
  2081. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  2082. {
  2083. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2084. }
  2085. if ($name !== null || $email !== null || $url !== null)
  2086. {
  2087. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  2088. }
  2089. }
  2090. if (!empty($contributors))
  2091. {
  2092. return array_unique($contributors);
  2093. }
  2094. else
  2095. {
  2096. return null;
  2097. }
  2098. }
  2099. /**
  2100. * Get a single link for the feed
  2101. *
  2102. * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
  2103. * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
  2104. * @param string $rel The relationship of the link to return
  2105. * @return string|null Link URL
  2106. */
  2107. public function get_link($key = 0, $rel = 'alternate')
  2108. {
  2109. $links = $this->get_links($rel);
  2110. if (isset($links[$key]))
  2111. {
  2112. return $links[$key];
  2113. }
  2114. else
  2115. {
  2116. return null;
  2117. }
  2118. }
  2119. /**
  2120. * Get the permalink for the item
  2121. *
  2122. * Returns the first link available with a relationship of "alternate".
  2123. * Identical to {@see get_link()} with key 0
  2124. *
  2125. * @see get_link
  2126. * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
  2127. * @internal Added for parity between the parent-level and the item/entry-level.
  2128. * @return string|null Link URL
  2129. */
  2130. public function get_permalink()
  2131. {
  2132. return $this->get_link(0);
  2133. }
  2134. /**
  2135. * Get all links for the feed
  2136. *
  2137. * Uses `<atom:link>` or `<link>`
  2138. *
  2139. * @since Beta 2
  2140. * @param string $rel The relationship of links to return
  2141. * @return array|null Links found for the feed (strings)
  2142. */
  2143. public function get_links($rel = 'alternate')
  2144. {
  2145. if (!isset($this->data['links']))
  2146. {
  2147. $this->data['links'] = array();
  2148. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  2149. {
  2150. foreach ($links as $link)
  2151. {
  2152. if (isset($link['attribs']['']['href']))
  2153. {
  2154. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2155. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2156. }
  2157. }
  2158. }
  2159. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  2160. {
  2161. foreach ($links as $link)
  2162. {
  2163. if (isset($link['attribs']['']['href']))
  2164. {
  2165. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  2166. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  2167. }
  2168. }
  2169. }
  2170. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  2171. {
  2172. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2173. }
  2174. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  2175. {
  2176. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2177. }
  2178. if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  2179. {
  2180. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  2181. }
  2182. $keys = array_keys($this->data['links']);
  2183. foreach ($keys as $key)
  2184. {
  2185. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  2186. {
  2187. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  2188. {
  2189. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  2190. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  2191. }
  2192. else
  2193. {
  2194. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  2195. }
  2196. }
  2197. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  2198. {
  2199. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  2200. }
  2201. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  2202. }
  2203. }
  2204. if (isset($this->data['links'][$rel]))
  2205. {
  2206. return $this->data['links'][$rel];
  2207. }
  2208. else
  2209. {
  2210. return null;
  2211. }
  2212. }
  2213. public function get_all_discovered_feeds()
  2214. {
  2215. return $this->all_discovered_feeds;
  2216. }
  2217. /**
  2218. * Get the content for the item
  2219. *
  2220. * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
  2221. * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
  2222. *
  2223. * @since 1.0 (previously called `get_feed_description()` since 0.8)
  2224. * @return string|null
  2225. */
  2226. public function get_description()
  2227. {
  2228. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  2229. {
  2230. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2231. }
  2232. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  2233. {
  2234. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2235. }
  2236. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  2237. {
  2238. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  2239. }
  2240. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  2241. {
  2242. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  2243. }
  2244. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  2245. {
  2246. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2247. }
  2248. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  2249. {
  2250. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2251. }
  2252. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  2253. {
  2254. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2255. }
  2256. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  2257. {
  2258. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2259. }
  2260. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  2261. {
  2262. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  2263. }
  2264. else
  2265. {
  2266. return null;
  2267. }
  2268. }
  2269. /**
  2270. * Get the copyright info for the feed
  2271. *
  2272. * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
  2273. *
  2274. * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
  2275. * @return string|null
  2276. */
  2277. public function get_copyright()
  2278. {
  2279. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  2280. {
  2281. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2282. }
  2283. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  2284. {
  2285. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  2286. }
  2287. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  2288. {
  2289. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2290. }
  2291. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  2292. {
  2293. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2294. }
  2295. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  2296. {
  2297. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2298. }
  2299. else
  2300. {
  2301. return null;
  2302. }
  2303. }
  2304. /**
  2305. * Get the language for the feed
  2306. *
  2307. * Uses `<language>`, `<dc:language>`, or @xml_lang
  2308. *
  2309. * @since 1.0 (previously called `get_feed_language()` since 0.8)
  2310. * @return string|null
  2311. */
  2312. public function get_language()
  2313. {
  2314. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  2315. {
  2316. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2317. }
  2318. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  2319. {
  2320. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2321. }
  2322. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  2323. {
  2324. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2325. }
  2326. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
  2327. {
  2328. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2329. }
  2330. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
  2331. {
  2332. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2333. }
  2334. elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
  2335. {
  2336. return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  2337. }
  2338. elseif (isset($this->data['headers']['content-language']))
  2339. {
  2340. return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
  2341. }
  2342. else
  2343. {
  2344. return null;
  2345. }
  2346. }
  2347. /**
  2348. * Get the latitude coordinates for the item
  2349. *
  2350. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  2351. *
  2352. * Uses `<geo:lat>` or `<georss:point>`
  2353. *
  2354. * @since 1.0
  2355. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  2356. * @link http://www.georss.org/ GeoRSS
  2357. * @return string|null
  2358. */
  2359. public function get_latitude()
  2360. {
  2361. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  2362. {
  2363. return (float) $return[0]['data'];
  2364. }
  2365. 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))
  2366. {
  2367. return (float) $match[1];
  2368. }
  2369. else
  2370. {
  2371. return null;
  2372. }
  2373. }
  2374. /**
  2375. * Get the longitude coordinates for the feed
  2376. *
  2377. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  2378. *
  2379. * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
  2380. *
  2381. * @since 1.0
  2382. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  2383. * @link http://www.georss.org/ GeoRSS
  2384. * @return string|null
  2385. */
  2386. public function get_longitude()
  2387. {
  2388. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  2389. {
  2390. return (float) $return[0]['data'];
  2391. }
  2392. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  2393. {
  2394. return (float) $return[0]['data'];
  2395. }
  2396. 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))
  2397. {
  2398. return (float) $match[2];
  2399. }
  2400. else
  2401. {
  2402. return null;
  2403. }
  2404. }
  2405. /**
  2406. * Get the feed logo's title
  2407. *
  2408. * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
  2409. *
  2410. * Uses `<image><title>` or `<image><dc:title>`
  2411. *
  2412. * @return string|null
  2413. */
  2414. public function get_image_title()
  2415. {
  2416. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  2417. {
  2418. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2419. }
  2420. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  2421. {
  2422. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2423. }
  2424. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  2425. {
  2426. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2427. }
  2428. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  2429. {
  2430. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2431. }
  2432. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  2433. {
  2434. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  2435. }
  2436. else
  2437. {
  2438. return null;
  2439. }
  2440. }
  2441. /**
  2442. * Get the feed logo's URL
  2443. *
  2444. * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
  2445. * have a "feed logo" URL. This points directly to the image itself.
  2446. *
  2447. * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
  2448. * `<image><title>` or `<image><dc:title>`
  2449. *
  2450. * @return string|null
  2451. */
  2452. public function get_image_url()
  2453. {
  2454. if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
  2455. {
  2456. return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
  2457. }
  2458. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  2459. {
  2460. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2461. }
  2462. elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  2463. {
  2464. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2465. }
  2466. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
  2467. {
  2468. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2469. }
  2470. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
  2471. {
  2472. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2473. }
  2474. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2475. {
  2476. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2477. }
  2478. else
  2479. {
  2480. return null;
  2481. }
  2482. }
  2483. /**
  2484. * Get the feed logo's link
  2485. *
  2486. * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
  2487. * points to a human-readable page that the image should link to.
  2488. *
  2489. * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
  2490. * `<image><title>` or `<image><dc:title>`
  2491. *
  2492. * @return string|null
  2493. */
  2494. public function get_image_link()
  2495. {
  2496. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  2497. {
  2498. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2499. }
  2500. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  2501. {
  2502. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2503. }
  2504. elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  2505. {
  2506. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  2507. }
  2508. else
  2509. {
  2510. return null;
  2511. }
  2512. }
  2513. /**
  2514. * Get the feed logo's link
  2515. *
  2516. * RSS 2.0 feeds are allowed to have a "feed logo" width.
  2517. *
  2518. * Uses `<image><width>` or defaults to 88.0 if no width is specified and
  2519. * the feed is an RSS 2.0 feed.
  2520. *
  2521. * @return int|float|null
  2522. */
  2523. public function get_image_width()
  2524. {
  2525. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
  2526. {
  2527. return round($return[0]['data']);
  2528. }
  2529. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2530. {
  2531. return 88.0;
  2532. }
  2533. else
  2534. {
  2535. return null;
  2536. }
  2537. }
  2538. /**
  2539. * Get the feed logo's height
  2540. *
  2541. * RSS 2.0 feeds are allowed to have a "feed logo" height.
  2542. *
  2543. * Uses `<image><height>` or defaults to 31.0 if no height is specified and
  2544. * the feed is an RSS 2.0 feed.
  2545. *
  2546. * @return int|float|null
  2547. */
  2548. public function get_image_height()
  2549. {
  2550. if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
  2551. {
  2552. return round($return[0]['data']);
  2553. }
  2554. elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
  2555. {
  2556. return 31.0;
  2557. }
  2558. else
  2559. {
  2560. return null;
  2561. }
  2562. }
  2563. /**
  2564. * Get the number of items in the feed
  2565. *
  2566. * This is well-suited for {@link http://php.net/for for()} loops with
  2567. * {@see get_item()}
  2568. *
  2569. * @param int $max Maximum value to return. 0 for no limit
  2570. * @return int Number of items in the feed
  2571. */
  2572. public function get_item_quantity($max = 0)
  2573. {
  2574. $max = (int) $max;
  2575. $qty = count($this->get_items());
  2576. if ($max === 0)
  2577. {
  2578. return $qty;
  2579. }
  2580. else
  2581. {
  2582. return ($qty > $max) ? $max : $qty;
  2583. }
  2584. }
  2585. /**
  2586. * Get a single item from the feed
  2587. *
  2588. * This is better suited for {@link http://php.net/for for()} loops, whereas
  2589. * {@see get_items()} is better suited for
  2590. * {@link http://php.net/foreach foreach()} loops.
  2591. *
  2592. * @see get_item_quantity()
  2593. * @since Beta 2
  2594. * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
  2595. * @return SimplePie_Item|null
  2596. */
  2597. public function get_item($key = 0)
  2598. {
  2599. $items = $this->get_items();
  2600. if (isset($items[$key]))
  2601. {
  2602. return $items[$key];
  2603. }
  2604. else
  2605. {
  2606. return null;
  2607. }
  2608. }
  2609. /**
  2610. * Get all items from the feed
  2611. *
  2612. * This is better suited for {@link http://php.net/for for()} loops, whereas
  2613. * {@see get_items()} is better suited for
  2614. * {@link http://php.net/foreach foreach()} loops.
  2615. *
  2616. * @see get_item_quantity
  2617. * @since Beta 2
  2618. * @param int $start Index to start at
  2619. * @param int $end Number of items to return. 0 for all items after `$start`
  2620. * @return array|null List of {@see SimplePie_Item} objects
  2621. */
  2622. public function get_items($start = 0, $end = 0)
  2623. {
  2624. if (!isset($this->data['items']))
  2625. {
  2626. if (!empty($this->multifeed_objects))
  2627. {
  2628. $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
  2629. }
  2630. else
  2631. {
  2632. $this->data['items'] = array();
  2633. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
  2634. {
  2635. $keys = array_keys($items);
  2636. foreach ($keys as $key)
  2637. {
  2638. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2639. }
  2640. }
  2641. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
  2642. {
  2643. $keys = array_keys($items);
  2644. foreach ($keys as $key)
  2645. {
  2646. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2647. }
  2648. }
  2649. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
  2650. {
  2651. $keys = array_keys($items);
  2652. foreach ($keys as $key)
  2653. {
  2654. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2655. }
  2656. }
  2657. if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
  2658. {
  2659. $keys = array_keys($items);
  2660. foreach ($keys as $key)
  2661. {
  2662. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2663. }
  2664. }
  2665. if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
  2666. {
  2667. $keys = array_keys($items);
  2668. foreach ($keys as $key)
  2669. {
  2670. $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
  2671. }
  2672. }
  2673. }
  2674. }
  2675. if (!empty($this->data['items']))
  2676. {
  2677. // If we want to order it by date, check if all items have a date, and then sort it
  2678. if ($this->order_by_date && empty($this->multifeed_objects))
  2679. {
  2680. if (!isset($this->data['ordered_items']))
  2681. {
  2682. $do_sort = true;
  2683. foreach ($this->data['items'] as $item)
  2684. {
  2685. if (!$item->get_date('U'))
  2686. {
  2687. $do_sort = false;
  2688. break;
  2689. }
  2690. }
  2691. $item = null;
  2692. $this->data['ordered_items'] = $this->data['items'];
  2693. if ($do_sort)
  2694. {
  2695. usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
  2696. }
  2697. }
  2698. $items = $this->data['ordered_items'];
  2699. }
  2700. else
  2701. {
  2702. $items = $this->data['items'];
  2703. }
  2704. // Slice the data as desired
  2705. if ($end === 0)
  2706. {
  2707. return array_slice($items, $start);
  2708. }
  2709. else
  2710. {
  2711. return array_slice($items, $start, $end);
  2712. }
  2713. }
  2714. else
  2715. {
  2716. return array();
  2717. }
  2718. }
  2719. /**
  2720. * Set the favicon handler
  2721. *
  2722. * @deprecated Use your own favicon handling instead
  2723. */
  2724. public function set_favicon_handler($page = false, $qs = 'i')
  2725. {
  2726. $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
  2727. trigger_error('Favicon handling has been removed, please use your own handling', $level);
  2728. return false;
  2729. }
  2730. /**
  2731. * Get the favicon for the current feed
  2732. *
  2733. * @deprecated Use your own favicon handling instead
  2734. */
  2735. public function get_favicon()
  2736. {
  2737. $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
  2738. trigger_error('Favicon handling has been removed, please use your own handling', $level);
  2739. if (($url = $this->get_link()) !== null)
  2740. {
  2741. return 'http://g.etfv.co/' . urlencode($url);
  2742. }
  2743. return false;
  2744. }
  2745. /**
  2746. * Magic method handler
  2747. *
  2748. * @param string $method Method name
  2749. * @param array $args Arguments to the method
  2750. * @return mixed
  2751. */
  2752. public function __call($method, $args)
  2753. {
  2754. if (strpos($method, 'subscribe_') === 0)
  2755. {
  2756. $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
  2757. trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
  2758. return '';
  2759. }
  2760. if ($method === 'enable_xml_dump')
  2761. {
  2762. $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
  2763. trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
  2764. return false;
  2765. }
  2766. $class = get_class($this);
  2767. $trace = debug_backtrace();
  2768. $file = $trace[0]['file'];
  2769. $line = $trace[0]['line'];
  2770. trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
  2771. }
  2772. /**
  2773. * Sorting callback for items
  2774. *
  2775. * @access private
  2776. * @param SimplePie $a
  2777. * @param SimplePie $b
  2778. * @return boolean
  2779. */
  2780. public static function sort_items($a, $b)
  2781. {
  2782. return $a->get_date('U') <= $b->get_date('U');
  2783. }
  2784. /**
  2785. * Merge items from several feeds into one
  2786. *
  2787. * If you're merging multiple feeds together, they need to all have dates
  2788. * for the items or else SimplePie will refuse to sort them.
  2789. *
  2790. * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
  2791. * @param array $urls List of SimplePie feed objects to merge
  2792. * @param int $start Starting item
  2793. * @param int $end Number of items to return
  2794. * @param int $limit Maximum number of items per feed
  2795. * @return array
  2796. */
  2797. public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
  2798. {
  2799. if (is_array($urls) && sizeof($urls) > 0)
  2800. {
  2801. $items = array();
  2802. foreach ($urls as $arg)
  2803. {
  2804. if ($arg instanceof SimplePie)
  2805. {
  2806. $items = array_merge($items, $arg->get_items(0, $limit));
  2807. }
  2808. else
  2809. {
  2810. trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
  2811. }
  2812. }
  2813. $do_sort = true;
  2814. foreach ($items as $item)
  2815. {
  2816. if (!$item->get_date('U'))
  2817. {
  2818. $do_sort = false;
  2819. break;
  2820. }
  2821. }
  2822. $item = null;
  2823. if ($do_sort)
  2824. {
  2825. usort($items, array(get_class($urls[0]), 'sort_items'));
  2826. }
  2827. if ($end === 0)
  2828. {
  2829. return array_slice($items, $start);
  2830. }
  2831. else
  2832. {
  2833. return array_slice($items, $start, $end);
  2834. }
  2835. }
  2836. else
  2837. {
  2838. trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
  2839. return array();
  2840. }
  2841. }
  2842. }
  2843. /**
  2844. * Manages `<media:copyright>` copyright tags as defined in Media RSS
  2845. *
  2846. * Used by {@see SimplePie_Enclosure::get_copyright()}
  2847. *
  2848. * This class can be overloaded with {@see SimplePie::set_copyright_class()}
  2849. *
  2850. * @package SimplePie
  2851. * @subpackage API
  2852. */
  2853. class SimplePie_Copyright
  2854. {
  2855. /**
  2856. * Copyright URL
  2857. *
  2858. * @var string
  2859. * @see get_url()
  2860. */
  2861. var $url;
  2862. /**
  2863. * Attribution
  2864. *
  2865. * @var string
  2866. * @see get_attribution()
  2867. */
  2868. var $label;
  2869. /**
  2870. * Constructor, used to input the data
  2871. *
  2872. * For documentation on all the parameters, see the corresponding
  2873. * properties and their accessors
  2874. */
  2875. public function __construct($url = null, $label = null)
  2876. {
  2877. $this->url = $url;
  2878. $this->label = $label;
  2879. }
  2880. /**
  2881. * String-ified version
  2882. *
  2883. * @return string
  2884. */
  2885. public function __toString()
  2886. {
  2887. // There is no $this->data here
  2888. return md5(serialize($this));
  2889. }
  2890. /**
  2891. * Get the copyright URL
  2892. *
  2893. * @return string|null URL to copyright information
  2894. */
  2895. public function get_url()
  2896. {
  2897. if ($this->url !== null)
  2898. {
  2899. return $this->url;
  2900. }
  2901. else
  2902. {
  2903. return null;
  2904. }
  2905. }
  2906. /**
  2907. * Get the attribution text
  2908. *
  2909. * @return string|null
  2910. */
  2911. public function get_attribution()
  2912. {
  2913. if ($this->label !== null)
  2914. {
  2915. return $this->label;
  2916. }
  2917. else
  2918. {
  2919. return null;
  2920. }
  2921. }
  2922. }
  2923. /**
  2924. * Used to create cache objects
  2925. *
  2926. * This class can be overloaded with {@see SimplePie::set_cache_class()},
  2927. * although the preferred way is to create your own handler
  2928. * via {@see register()}
  2929. *
  2930. * @package SimplePie
  2931. * @subpackage Caching
  2932. */
  2933. class SimplePie_Cache
  2934. {
  2935. /**
  2936. * Cache handler classes
  2937. *
  2938. * These receive 3 parameters to their constructor, as documented in
  2939. * {@see register()}
  2940. * @var array
  2941. */
  2942. protected static $handlers = array(
  2943. 'mysql' => 'SimplePie_Cache_MySQL',
  2944. 'memcache' => 'SimplePie_Cache_Memcache',
  2945. );
  2946. /**
  2947. * Don't call the constructor. Please.
  2948. */
  2949. private function __construct() { }
  2950. /**
  2951. * Create a new SimplePie_Cache object
  2952. *
  2953. * @param string $location URL location (scheme is used to determine handler)
  2954. * @param string $filename Unique identifier for cache object
  2955. * @param string $extension 'spi' or 'spc'
  2956. * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
  2957. */
  2958. public static function get_handler($location, $filename, $extension)
  2959. {
  2960. $type = explode(':', $location, 2);
  2961. $type = $type[0];
  2962. if (!empty(self::$handlers[$type]))
  2963. {
  2964. $class = self::$handlers[$type];
  2965. return new $class($location, $filename, $extension);
  2966. }
  2967. return new SimplePie_Cache_File($location, $filename, $extension);
  2968. }
  2969. /**
  2970. * Create a new SimplePie_Cache object
  2971. *
  2972. * @deprecated Use {@see get_handler} instead
  2973. */
  2974. public function create($location, $filename, $extension)
  2975. {
  2976. trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
  2977. return self::get_handler($location, $filename, $extension);
  2978. }
  2979. /**
  2980. * Register a handler
  2981. *
  2982. * @param string $type DSN type to register for
  2983. * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
  2984. */
  2985. public static function register($type, $class)
  2986. {
  2987. self::$handlers[$type] = $class;
  2988. }
  2989. /**
  2990. * Parse a URL into an array
  2991. *
  2992. * @param string $url
  2993. * @return array
  2994. */
  2995. public static function parse_URL($url)
  2996. {
  2997. $params = parse_url($url);
  2998. $params['extras'] = array();
  2999. if (isset($params['query']))
  3000. {
  3001. parse_str($params['query'], $params['extras']);
  3002. }
  3003. return $params;
  3004. }
  3005. }
  3006. /**
  3007. * Handles creating objects and calling methods
  3008. *
  3009. * Access this via {@see SimplePie::get_registry()}
  3010. *
  3011. * @package SimplePie
  3012. */
  3013. class SimplePie_Registry
  3014. {
  3015. /**
  3016. * Default class mapping
  3017. *
  3018. * Overriding classes *must* subclass these.
  3019. *
  3020. * @var array
  3021. */
  3022. protected $default = array(
  3023. 'Cache' => 'SimplePie_Cache',
  3024. 'Locator' => 'SimplePie_Locator',
  3025. 'Parser' => 'SimplePie_Parser',
  3026. 'File' => 'SimplePie_File',
  3027. 'Sanitize' => 'SimplePie_Sanitize',
  3028. 'Item' => 'SimplePie_Item',
  3029. 'Author' => 'SimplePie_Author',
  3030. 'Category' => 'SimplePie_Category',
  3031. 'Enclosure' => 'SimplePie_Enclosure',
  3032. 'Caption' => 'SimplePie_Caption',
  3033. 'Copyright' => 'SimplePie_Copyright',
  3034. 'Credit' => 'SimplePie_Credit',
  3035. 'Rating' => 'SimplePie_Rating',
  3036. 'Restriction' => 'SimplePie_Restriction',
  3037. 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
  3038. 'Source' => 'SimplePie_Source',
  3039. 'Misc' => 'SimplePie_Misc',
  3040. 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
  3041. 'Parse_Date' => 'SimplePie_Parse_Date',
  3042. );
  3043. /**
  3044. * Class mapping
  3045. *
  3046. * @see register()
  3047. * @var array
  3048. */
  3049. protected $classes = array();
  3050. /**
  3051. * Legacy classes
  3052. *
  3053. * @see register()
  3054. * @var array
  3055. */
  3056. protected $legacy = array();
  3057. /**
  3058. * Constructor
  3059. *
  3060. * No-op
  3061. */
  3062. public function __construct() { }
  3063. /**
  3064. * Register a class
  3065. *
  3066. * @param string $type See {@see $default} for names
  3067. * @param string $class Class name, must subclass the corresponding default
  3068. * @param bool $legacy Whether to enable legacy support for this class
  3069. * @return bool Successfulness
  3070. */
  3071. public function register($type, $class, $legacy = false)
  3072. {
  3073. if (!is_subclass_of($class, $this->default[$type]))
  3074. {
  3075. return false;
  3076. }
  3077. $this->classes[$type] = $class;
  3078. if ($legacy)
  3079. {
  3080. $this->legacy[] = $class;
  3081. }
  3082. return true;
  3083. }
  3084. /**
  3085. * Get the class registered for a type
  3086. *
  3087. * Where possible, use {@see create()} or {@see call()} instead
  3088. *
  3089. * @param string $type
  3090. * @return string|null
  3091. */
  3092. public function get_class($type)
  3093. {
  3094. if (!empty($this->classes[$type]))
  3095. {
  3096. return $this->classes[$type];
  3097. }
  3098. if (!empty($this->default[$type]))
  3099. {
  3100. return $this->default[$type];
  3101. }
  3102. return null;
  3103. }
  3104. /**
  3105. * Create a new instance of a given type
  3106. *
  3107. * @param string $type
  3108. * @param array $parameters Parameters to pass to the constructor
  3109. * @return object Instance of class
  3110. */
  3111. public function &create($type, $parameters = array())
  3112. {
  3113. $class = $this->get_class($type);
  3114. if (in_array($class, $this->legacy))
  3115. {
  3116. switch ($type)
  3117. {
  3118. case 'locator':
  3119. // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
  3120. // Specified: file, timeout, useragent, max_checked_feeds
  3121. $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
  3122. array_splice($parameters, 3, 1, $replacement);
  3123. break;
  3124. }
  3125. }
  3126. if (!method_exists($class, '__construct'))
  3127. {
  3128. $instance = new $class;
  3129. }
  3130. else
  3131. {
  3132. $reflector = new ReflectionClass($class);
  3133. $instance = $reflector->newInstanceArgs($parameters);
  3134. }
  3135. if (method_exists($instance, 'set_registry'))
  3136. {
  3137. $instance->set_registry($this);
  3138. }
  3139. return $instance;
  3140. }
  3141. /**
  3142. * Call a static method for a type
  3143. *
  3144. * @param string $type
  3145. * @param string $method
  3146. * @param array $parameters
  3147. * @return mixed
  3148. */
  3149. public function &call($type, $method, $parameters = array())
  3150. {
  3151. $class = $this->get_class($type);
  3152. if (in_array($class, $this->legacy))
  3153. {
  3154. switch ($type)
  3155. {
  3156. case 'Cache':
  3157. // For backwards compatibility with old non-static
  3158. // Cache::create() methods
  3159. if ($method === 'get_handler')
  3160. {
  3161. $result = @call_user_func_array(array($class, 'create'), $parameters);
  3162. return $result;
  3163. }
  3164. break;
  3165. }
  3166. }
  3167. $result = call_user_func_array(array($class, $method), $parameters);
  3168. return $result;
  3169. }
  3170. }
  3171. /**
  3172. * Base class for database-based caches
  3173. *
  3174. * @package SimplePie
  3175. * @subpackage Caching
  3176. */
  3177. abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
  3178. {
  3179. /**
  3180. * Helper for database conversion
  3181. *
  3182. * Converts a given {@see SimplePie} object into data to be stored
  3183. *
  3184. * @param SimplePie $data
  3185. * @return array First item is the serialized data for storage, second item is the unique ID for this item
  3186. */
  3187. protected static function prepare_simplepie_object_for_cache($data)
  3188. {
  3189. $items = $data->get_items();
  3190. $items_by_id = array();
  3191. if (!empty($items))
  3192. {
  3193. foreach ($items as $item)
  3194. {
  3195. $items_by_id[$item->get_id()] = $item;
  3196. }
  3197. if (count($items_by_id) !== count($items))
  3198. {
  3199. $items_by_id = array();
  3200. foreach ($items as $item)
  3201. {
  3202. $items_by_id[$item->get_id(true)] = $item;
  3203. }
  3204. }
  3205. if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
  3206. {
  3207. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
  3208. }
  3209. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
  3210. {
  3211. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
  3212. }
  3213. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
  3214. {
  3215. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
  3216. }
  3217. elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
  3218. {
  3219. $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
  3220. }
  3221. else
  3222. {
  3223. $channel = null;
  3224. }
  3225. if ($channel !== null)
  3226. {
  3227. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
  3228. {
  3229. unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
  3230. }
  3231. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
  3232. {
  3233. unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
  3234. }
  3235. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
  3236. {
  3237. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
  3238. }
  3239. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
  3240. {
  3241. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
  3242. }
  3243. if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
  3244. {
  3245. unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
  3246. }
  3247. }
  3248. if (isset($data->data['items']))
  3249. {
  3250. unset($data->data['items']);
  3251. }
  3252. if (isset($data->data['ordered_items']))
  3253. {
  3254. unset($data->data['ordered_items']);
  3255. }
  3256. }
  3257. return array(serialize($data->data), $items_by_id);
  3258. }
  3259. }
  3260. /**
  3261. * Caches data to the filesystem
  3262. *
  3263. * @package SimplePie
  3264. * @subpackage Caching
  3265. */
  3266. class SimplePie_Cache_File implements SimplePie_Cache_Base
  3267. {
  3268. /**
  3269. * Location string
  3270. *
  3271. * @see SimplePie::$cache_location
  3272. * @var string
  3273. */
  3274. protected $location;
  3275. /**
  3276. * Filename
  3277. *
  3278. * @var string
  3279. */
  3280. protected $filename;
  3281. /**
  3282. * File extension
  3283. *
  3284. * @var string
  3285. */
  3286. protected $extension;
  3287. /**
  3288. * File path
  3289. *
  3290. * @var string
  3291. */
  3292. protected $name;
  3293. /**
  3294. * Create a new cache object
  3295. *
  3296. * @param string $location Location string (from SimplePie::$cache_location)
  3297. * @param string $name Unique ID for the cache
  3298. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3299. */
  3300. public function __construct($location, $name, $type)
  3301. {
  3302. $this->location = $location;
  3303. $this->filename = $name;
  3304. $this->extension = $type;
  3305. $this->name = "$this->location/$this->filename.$this->extension";
  3306. }
  3307. /**
  3308. * Save data to the cache
  3309. *
  3310. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3311. * @return bool Successfulness
  3312. */
  3313. public function save($data)
  3314. {
  3315. if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
  3316. {
  3317. if ($data instanceof SimplePie)
  3318. {
  3319. $data = $data->data;
  3320. }
  3321. $data = serialize($data);
  3322. return (bool) file_put_contents($this->name, $data);
  3323. }
  3324. return false;
  3325. }
  3326. /**
  3327. * Retrieve the data saved to the cache
  3328. *
  3329. * @return array Data for SimplePie::$data
  3330. */
  3331. public function load()
  3332. {
  3333. if (file_exists($this->name) && is_readable($this->name))
  3334. {
  3335. return unserialize(file_get_contents($this->name));
  3336. }
  3337. return false;
  3338. }
  3339. /**
  3340. * Retrieve the last modified time for the cache
  3341. *
  3342. * @return int Timestamp
  3343. */
  3344. public function mtime()
  3345. {
  3346. if (file_exists($this->name))
  3347. {
  3348. return filemtime($this->name);
  3349. }
  3350. return false;
  3351. }
  3352. /**
  3353. * Set the last modified time to the current time
  3354. *
  3355. * @return bool Success status
  3356. */
  3357. public function touch()
  3358. {
  3359. if (file_exists($this->name))
  3360. {
  3361. return touch($this->name);
  3362. }
  3363. return false;
  3364. }
  3365. /**
  3366. * Remove the cache
  3367. *
  3368. * @return bool Success status
  3369. */
  3370. public function unlink()
  3371. {
  3372. if (file_exists($this->name))
  3373. {
  3374. return unlink($this->name);
  3375. }
  3376. return false;
  3377. }
  3378. }
  3379. /**
  3380. * Base for cache objects
  3381. *
  3382. * Classes to be used with {@see SimplePie_Cache::register()} are expected
  3383. * to implement this interface.
  3384. *
  3385. * @package SimplePie
  3386. * @subpackage Caching
  3387. */
  3388. interface SimplePie_Cache_Base
  3389. {
  3390. /**
  3391. * Feed cache type
  3392. *
  3393. * @var string
  3394. */
  3395. const TYPE_FEED = 'spc';
  3396. /**
  3397. * Image cache type
  3398. *
  3399. * @var string
  3400. */
  3401. const TYPE_IMAGE = 'spi';
  3402. /**
  3403. * Create a new cache object
  3404. *
  3405. * @param string $location Location string (from SimplePie::$cache_location)
  3406. * @param string $name Unique ID for the cache
  3407. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3408. */
  3409. public function __construct($location, $name, $type);
  3410. /**
  3411. * Save data to the cache
  3412. *
  3413. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3414. * @return bool Successfulness
  3415. */
  3416. public function save($data);
  3417. /**
  3418. * Retrieve the data saved to the cache
  3419. *
  3420. * @return array Data for SimplePie::$data
  3421. */
  3422. public function load();
  3423. /**
  3424. * Retrieve the last modified time for the cache
  3425. *
  3426. * @return int Timestamp
  3427. */
  3428. public function mtime();
  3429. /**
  3430. * Set the last modified time to the current time
  3431. *
  3432. * @return bool Success status
  3433. */
  3434. public function touch();
  3435. /**
  3436. * Remove the cache
  3437. *
  3438. * @return bool Success status
  3439. */
  3440. public function unlink();
  3441. }
  3442. /**
  3443. * Caches data to memcache
  3444. *
  3445. * Registered for URLs with the "memcache" protocol
  3446. *
  3447. * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
  3448. * connect to memcache on `localhost` on port 11211. All tables will be
  3449. * prefixed with `sp_` and data will expire after 3600 seconds
  3450. *
  3451. * @package SimplePie
  3452. * @subpackage Caching
  3453. * @uses Memcache
  3454. */
  3455. class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
  3456. {
  3457. /**
  3458. * Memcache instance
  3459. *
  3460. * @var Memcache
  3461. */
  3462. protected $cache;
  3463. /**
  3464. * Options
  3465. *
  3466. * @var array
  3467. */
  3468. protected $options;
  3469. /**
  3470. * Cache name
  3471. *
  3472. * @var string
  3473. */
  3474. protected $name;
  3475. /**
  3476. * Create a new cache object
  3477. *
  3478. * @param string $location Location string (from SimplePie::$cache_location)
  3479. * @param string $name Unique ID for the cache
  3480. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3481. */
  3482. public function __construct($location, $name, $type)
  3483. {
  3484. $this->options = array(
  3485. 'host' => '127.0.0.1',
  3486. 'port' => 11211,
  3487. 'extras' => array(
  3488. 'timeout' => 3600, // one hour
  3489. 'prefix' => 'simplepie_',
  3490. ),
  3491. );
  3492. $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
  3493. $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
  3494. $this->cache = new Memcache();
  3495. $this->cache->addServer($this->options['host'], (int) $this->options['port']);
  3496. }
  3497. /**
  3498. * Save data to the cache
  3499. *
  3500. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3501. * @return bool Successfulness
  3502. */
  3503. public function save($data)
  3504. {
  3505. if ($data instanceof SimplePie)
  3506. {
  3507. $data = $data->data;
  3508. }
  3509. return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
  3510. }
  3511. /**
  3512. * Retrieve the data saved to the cache
  3513. *
  3514. * @return array Data for SimplePie::$data
  3515. */
  3516. public function load()
  3517. {
  3518. $data = $this->cache->get($this->name);
  3519. if ($data !== false)
  3520. {
  3521. return unserialize($data);
  3522. }
  3523. return false;
  3524. }
  3525. /**
  3526. * Retrieve the last modified time for the cache
  3527. *
  3528. * @return int Timestamp
  3529. */
  3530. public function mtime()
  3531. {
  3532. $data = $this->cache->get($this->name);
  3533. if ($data !== false)
  3534. {
  3535. // essentially ignore the mtime because Memcache expires on its own
  3536. return time();
  3537. }
  3538. return false;
  3539. }
  3540. /**
  3541. * Set the last modified time to the current time
  3542. *
  3543. * @return bool Success status
  3544. */
  3545. public function touch()
  3546. {
  3547. $data = $this->cache->get($this->name);
  3548. if ($data !== false)
  3549. {
  3550. return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
  3551. }
  3552. return false;
  3553. }
  3554. /**
  3555. * Remove the cache
  3556. *
  3557. * @return bool Success status
  3558. */
  3559. public function unlink()
  3560. {
  3561. return $this->cache->delete($this->name, 0);
  3562. }
  3563. }
  3564. /**
  3565. * Caches data to a MySQL database
  3566. *
  3567. * Registered for URLs with the "mysql" protocol
  3568. *
  3569. * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
  3570. * connect to the `mydb` database on `localhost` on port 3306, with the user
  3571. * `root` and the password `password`. All tables will be prefixed with `sp_`
  3572. *
  3573. * @package SimplePie
  3574. * @subpackage Caching
  3575. */
  3576. class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
  3577. {
  3578. /**
  3579. * PDO instance
  3580. *
  3581. * @var PDO
  3582. */
  3583. protected $mysql;
  3584. /**
  3585. * Options
  3586. *
  3587. * @var array
  3588. */
  3589. protected $options;
  3590. /**
  3591. * Cache ID
  3592. *
  3593. * @var string
  3594. */
  3595. protected $id;
  3596. /**
  3597. * Create a new cache object
  3598. *
  3599. * @param string $location Location string (from SimplePie::$cache_location)
  3600. * @param string $name Unique ID for the cache
  3601. * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
  3602. */
  3603. public function __construct($location, $name, $type)
  3604. {
  3605. $this->options = array(
  3606. 'user' => null,
  3607. 'pass' => null,
  3608. 'host' => '127.0.0.1',
  3609. 'port' => '3306',
  3610. 'path' => '',
  3611. 'extras' => array(
  3612. 'prefix' => '',
  3613. ),
  3614. );
  3615. $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
  3616. // Path is prefixed with a "/"
  3617. $this->options['dbname'] = substr($this->options['path'], 1);
  3618. try
  3619. {
  3620. $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'));
  3621. }
  3622. catch (PDOException $e)
  3623. {
  3624. $this->mysql = null;
  3625. return;
  3626. }
  3627. $this->id = $name . $type;
  3628. if (!$query = $this->mysql->query('SHOW TABLES'))
  3629. {
  3630. $this->mysql = null;
  3631. return;
  3632. }
  3633. $db = array();
  3634. while ($row = $query->fetchColumn())
  3635. {
  3636. $db[] = $row;
  3637. }
  3638. if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
  3639. {
  3640. $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)))');
  3641. if ($query === false)
  3642. {
  3643. $this->mysql = null;
  3644. }
  3645. }
  3646. if (!in_array($this->options['extras']['prefix'] . 'items', $db))
  3647. {
  3648. $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)))');
  3649. if ($query === false)
  3650. {
  3651. $this->mysql = null;
  3652. }
  3653. }
  3654. }
  3655. /**
  3656. * Save data to the cache
  3657. *
  3658. * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
  3659. * @return bool Successfulness
  3660. */
  3661. public function save($data)
  3662. {
  3663. if ($this->mysql === null)
  3664. {
  3665. return false;
  3666. }
  3667. if ($data instanceof SimplePie)
  3668. {
  3669. $data = clone $data;
  3670. $prepared = self::prepare_simplepie_object_for_cache($data);
  3671. $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
  3672. $query->bindValue(':feed', $this->id);
  3673. if ($query->execute())
  3674. {
  3675. if ($query->fetchColumn() > 0)
  3676. {
  3677. $items = count($prepared[1]);
  3678. if ($items)
  3679. {
  3680. $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
  3681. $query = $this->mysql->prepare($sql);
  3682. $query->bindValue(':items', $items);
  3683. }
  3684. else
  3685. {
  3686. $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
  3687. $query = $this->mysql->prepare($sql);
  3688. }
  3689. $query->bindValue(':data', $prepared[0]);
  3690. $query->bindValue(':time', time());
  3691. $query->bindValue(':feed', $this->id);
  3692. if (!$query->execute())
  3693. {
  3694. return false;
  3695. }
  3696. }
  3697. else
  3698. {
  3699. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
  3700. $query->bindValue(':feed', $this->id);
  3701. $query->bindValue(':count', count($prepared[1]));
  3702. $query->bindValue(':data', $prepared[0]);
  3703. $query->bindValue(':time', time());
  3704. if (!$query->execute())
  3705. {
  3706. return false;
  3707. }
  3708. }
  3709. $ids = array_keys($prepared[1]);
  3710. if (!empty($ids))
  3711. {
  3712. foreach ($ids as $id)
  3713. {
  3714. $database_ids[] = $this->mysql->quote($id);
  3715. }
  3716. $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
  3717. $query->bindValue(':feed', $this->id);
  3718. if ($query->execute())
  3719. {
  3720. $existing_ids = array();
  3721. while ($row = $query->fetchColumn())
  3722. {
  3723. $existing_ids[] = $row;
  3724. }
  3725. $new_ids = array_diff($ids, $existing_ids);
  3726. foreach ($new_ids as $new_id)
  3727. {
  3728. if (!($date = $prepared[1][$new_id]->get_date('U')))
  3729. {
  3730. $date = time();
  3731. }
  3732. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
  3733. $query->bindValue(':feed', $this->id);
  3734. $query->bindValue(':id', $new_id);
  3735. $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
  3736. $query->bindValue(':date', $date);
  3737. if (!$query->execute())
  3738. {
  3739. return false;
  3740. }
  3741. }
  3742. return true;
  3743. }
  3744. }
  3745. else
  3746. {
  3747. return true;
  3748. }
  3749. }
  3750. }
  3751. else
  3752. {
  3753. $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
  3754. $query->bindValue(':feed', $this->id);
  3755. if ($query->execute())
  3756. {
  3757. if ($query->rowCount() > 0)
  3758. {
  3759. $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
  3760. $query->bindValue(':data', serialize($data));
  3761. $query->bindValue(':time', time());
  3762. $query->bindValue(':feed', $this->id);
  3763. if ($this->execute())
  3764. {
  3765. return true;
  3766. }
  3767. }
  3768. else
  3769. {
  3770. $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
  3771. $query->bindValue(':id', $this->id);
  3772. $query->bindValue(':data', serialize($data));
  3773. $query->bindValue(':time', time());
  3774. if ($query->execute())
  3775. {
  3776. return true;
  3777. }
  3778. }
  3779. }
  3780. }
  3781. return false;
  3782. }
  3783. /**
  3784. * Retrieve the data saved to the cache
  3785. *
  3786. * @return array Data for SimplePie::$data
  3787. */
  3788. public function load()
  3789. {
  3790. if ($this->mysql === null)
  3791. {
  3792. return false;
  3793. }
  3794. $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3795. $query->bindValue(':id', $this->id);
  3796. if ($query->execute() && ($row = $query->fetch()))
  3797. {
  3798. $data = unserialize($row[1]);
  3799. if (isset($this->options['items'][0]))
  3800. {
  3801. $items = (int) $this->options['items'][0];
  3802. }
  3803. else
  3804. {
  3805. $items = (int) $row[0];
  3806. }
  3807. if ($items !== 0)
  3808. {
  3809. if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
  3810. {
  3811. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
  3812. }
  3813. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
  3814. {
  3815. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
  3816. }
  3817. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
  3818. {
  3819. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
  3820. }
  3821. elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
  3822. {
  3823. $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
  3824. }
  3825. else
  3826. {
  3827. $feed = null;
  3828. }
  3829. if ($feed !== null)
  3830. {
  3831. $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
  3832. if ($items > 0)
  3833. {
  3834. $sql .= ' LIMIT ' . $items;
  3835. }
  3836. $query = $this->mysql->prepare($sql);
  3837. $query->bindValue(':feed', $this->id);
  3838. if ($query->execute())
  3839. {
  3840. while ($row = $query->fetchColumn())
  3841. {
  3842. $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
  3843. }
  3844. }
  3845. else
  3846. {
  3847. return false;
  3848. }
  3849. }
  3850. }
  3851. return $data;
  3852. }
  3853. return false;
  3854. }
  3855. /**
  3856. * Retrieve the last modified time for the cache
  3857. *
  3858. * @return int Timestamp
  3859. */
  3860. public function mtime()
  3861. {
  3862. if ($this->mysql === null)
  3863. {
  3864. return false;
  3865. }
  3866. $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3867. $query->bindValue(':id', $this->id);
  3868. if ($query->execute() && ($time = $query->fetchColumn()))
  3869. {
  3870. return $time;
  3871. }
  3872. else
  3873. {
  3874. return false;
  3875. }
  3876. }
  3877. /**
  3878. * Set the last modified time to the current time
  3879. *
  3880. * @return bool Success status
  3881. */
  3882. public function touch()
  3883. {
  3884. if ($this->mysql === null)
  3885. {
  3886. return false;
  3887. }
  3888. $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
  3889. $query->bindValue(':time', time());
  3890. $query->bindValue(':id', $this->id);
  3891. if ($query->execute() && $query->rowCount() > 0)
  3892. {
  3893. return true;
  3894. }
  3895. else
  3896. {
  3897. return false;
  3898. }
  3899. }
  3900. /**
  3901. * Remove the cache
  3902. *
  3903. * @return bool Success status
  3904. */
  3905. public function unlink()
  3906. {
  3907. if ($this->mysql === null)
  3908. {
  3909. return false;
  3910. }
  3911. $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
  3912. $query->bindValue(':id', $this->id);
  3913. $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
  3914. $query2->bindValue(':id', $this->id);
  3915. if ($query->execute() && $query2->execute())
  3916. {
  3917. return true;
  3918. }
  3919. else
  3920. {
  3921. return false;
  3922. }
  3923. }
  3924. }
  3925. /**
  3926. * Used for data cleanup and post-processing
  3927. *
  3928. *
  3929. * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
  3930. *
  3931. * @package SimplePie
  3932. * @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
  3933. */
  3934. class SimplePie_Sanitize
  3935. {
  3936. // Private vars
  3937. var $base;
  3938. // Options
  3939. var $remove_div = true;
  3940. var $image_handler = '';
  3941. var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
  3942. var $encode_instead_of_strip = false;
  3943. var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
  3944. var $strip_comments = false;
  3945. var $output_encoding = 'UTF-8';
  3946. var $enable_cache = true;
  3947. var $cache_location = './cache';
  3948. var $cache_name_function = 'md5';
  3949. var $timeout = 10;
  3950. var $useragent = '';
  3951. var $force_fsockopen = false;
  3952. var $replace_url_attributes = null;
  3953. public function __construct()
  3954. {
  3955. // Set defaults
  3956. $this->set_url_replacements(null);
  3957. }
  3958. public function remove_div($enable = true)
  3959. {
  3960. $this->remove_div = (bool) $enable;
  3961. }
  3962. public function set_image_handler($page = false)
  3963. {
  3964. if ($page)
  3965. {
  3966. $this->image_handler = (string) $page;
  3967. }
  3968. else
  3969. {
  3970. $this->image_handler = false;
  3971. }
  3972. }
  3973. public function set_registry(SimplePie_Registry $registry)
  3974. {
  3975. $this->registry = $registry;
  3976. }
  3977. public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
  3978. {
  3979. if (isset($enable_cache))
  3980. {
  3981. $this->enable_cache = (bool) $enable_cache;
  3982. }
  3983. if ($cache_location)
  3984. {
  3985. $this->cache_location = (string) $cache_location;
  3986. }
  3987. if ($cache_name_function)
  3988. {
  3989. $this->cache_name_function = (string) $cache_name_function;
  3990. }
  3991. }
  3992. public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
  3993. {
  3994. if ($timeout)
  3995. {
  3996. $this->timeout = (string) $timeout;
  3997. }
  3998. if ($useragent)
  3999. {
  4000. $this->useragent = (string) $useragent;
  4001. }
  4002. if ($force_fsockopen)
  4003. {
  4004. $this->force_fsockopen = (string) $force_fsockopen;
  4005. }
  4006. }
  4007. 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'))
  4008. {
  4009. if ($tags)
  4010. {
  4011. if (is_array($tags))
  4012. {
  4013. $this->strip_htmltags = $tags;
  4014. }
  4015. else
  4016. {
  4017. $this->strip_htmltags = explode(',', $tags);
  4018. }
  4019. }
  4020. else
  4021. {
  4022. $this->strip_htmltags = false;
  4023. }
  4024. }
  4025. public function encode_instead_of_strip($encode = false)
  4026. {
  4027. $this->encode_instead_of_strip = (bool) $encode;
  4028. }
  4029. public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
  4030. {
  4031. if ($attribs)
  4032. {
  4033. if (is_array($attribs))
  4034. {
  4035. $this->strip_attributes = $attribs;
  4036. }
  4037. else
  4038. {
  4039. $this->strip_attributes = explode(',', $attribs);
  4040. }
  4041. }
  4042. else
  4043. {
  4044. $this->strip_attributes = false;
  4045. }
  4046. }
  4047. public function strip_comments($strip = false)
  4048. {
  4049. $this->strip_comments = (bool) $strip;
  4050. }
  4051. public function set_output_encoding($encoding = 'UTF-8')
  4052. {
  4053. $this->output_encoding = (string) $encoding;
  4054. }
  4055. /**
  4056. * Set element/attribute key/value pairs of HTML attributes
  4057. * containing URLs that need to be resolved relative to the feed
  4058. *
  4059. * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
  4060. * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
  4061. * |q|@cite
  4062. *
  4063. * @since 1.0
  4064. * @param array|null $element_attribute Element/attribute key/value pairs, null for default
  4065. */
  4066. public function set_url_replacements($element_attribute = null)
  4067. {
  4068. if ($element_attribute === null)
  4069. {
  4070. $element_attribute = array(
  4071. 'a' => 'href',
  4072. 'area' => 'href',
  4073. 'blockquote' => 'cite',
  4074. 'del' => 'cite',
  4075. 'form' => 'action',
  4076. 'img' => array(
  4077. 'longdesc',
  4078. 'src'
  4079. ),
  4080. 'input' => 'src',
  4081. 'ins' => 'cite',
  4082. 'q' => 'cite'
  4083. );
  4084. }
  4085. $this->replace_url_attributes = (array) $element_attribute;
  4086. }
  4087. public function sanitize($data, $type, $base = '')
  4088. {
  4089. $data = trim($data);
  4090. if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
  4091. {
  4092. if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
  4093. {
  4094. 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))
  4095. {
  4096. $type |= SIMPLEPIE_CONSTRUCT_HTML;
  4097. }
  4098. else
  4099. {
  4100. $type |= SIMPLEPIE_CONSTRUCT_TEXT;
  4101. }
  4102. }
  4103. if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
  4104. {
  4105. $data = base64_decode($data);
  4106. }
  4107. if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
  4108. {
  4109. if (!class_exists('DOMDocument'))
  4110. {
  4111. throw new SimplePie_Exception('DOMDocument not found, unable to use sanitizer');
  4112. }
  4113. $document = new DOMDocument();
  4114. $document->encoding = 'UTF-8';
  4115. $data = $this->preprocess($data, $type);
  4116. set_error_handler(array('SimplePie_Misc', 'silence_errors'));
  4117. $document->loadHTML($data);
  4118. restore_error_handler();
  4119. // Strip comments
  4120. if ($this->strip_comments)
  4121. {
  4122. $xpath = new DOMXPath($document);
  4123. $comments = $xpath->query('//comment()');
  4124. foreach ($comments as $comment)
  4125. {
  4126. $comment->parentNode->removeChild($comment);
  4127. }
  4128. }
  4129. // Strip out HTML tags and attributes that might cause various security problems.
  4130. // Based on recommendations by Mark Pilgrim at:
  4131. // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
  4132. if ($this->strip_htmltags)
  4133. {
  4134. foreach ($this->strip_htmltags as $tag)
  4135. {
  4136. $this->strip_tag($tag, $document, $type);
  4137. }
  4138. }
  4139. if ($this->strip_attributes)
  4140. {
  4141. foreach ($this->strip_attributes as $attrib)
  4142. {
  4143. $this->strip_attr($attrib, $document);
  4144. }
  4145. }
  4146. // Replace relative URLs
  4147. $this->base = $base;
  4148. foreach ($this->replace_url_attributes as $element => $attributes)
  4149. {
  4150. $this->replace_urls($document, $element, $attributes);
  4151. }
  4152. // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
  4153. if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
  4154. {
  4155. $images = $document->getElementsByTagName('img');
  4156. foreach ($images as $img)
  4157. {
  4158. if ($img->hasAttribute('src'))
  4159. {
  4160. $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
  4161. $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
  4162. if ($cache->load())
  4163. {
  4164. $img->setAttribute('src', $this->image_handler . $image_url);
  4165. }
  4166. else
  4167. {
  4168. $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));
  4169. $headers = $file->headers;
  4170. if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
  4171. {
  4172. if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
  4173. {
  4174. $img->setAttribute('src', $this->image_handler . $image_url);
  4175. }
  4176. else
  4177. {
  4178. 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);
  4179. }
  4180. }
  4181. }
  4182. }
  4183. }
  4184. }
  4185. // Remove the DOCTYPE
  4186. // Seems to cause segfaulting if we don't do this
  4187. if ($document->firstChild instanceof DOMDocumentType)
  4188. {
  4189. $document->removeChild($document->firstChild);
  4190. }
  4191. // Move everything from the body to the root
  4192. $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
  4193. $document->replaceChild($real_body, $document->firstChild);
  4194. // Finally, convert to a HTML string
  4195. $data = trim($document->saveHTML());
  4196. if ($this->remove_div)
  4197. {
  4198. $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
  4199. $data = preg_replace('/<\/div>$/', '', $data);
  4200. }
  4201. else
  4202. {
  4203. $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
  4204. }
  4205. }
  4206. if ($type & SIMPLEPIE_CONSTRUCT_IRI)
  4207. {
  4208. $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
  4209. if ($absolute !== false)
  4210. {
  4211. $data = $absolute;
  4212. }
  4213. }
  4214. if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
  4215. {
  4216. $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
  4217. }
  4218. if ($this->output_encoding !== 'UTF-8')
  4219. {
  4220. $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
  4221. }
  4222. }
  4223. return $data;
  4224. }
  4225. protected function preprocess($html, $type)
  4226. {
  4227. $ret = '';
  4228. if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
  4229. {
  4230. // Atom XHTML constructs are wrapped with a div by default
  4231. // Note: No protection if $html contains a stray </div>!
  4232. $html = '<div>' . $html . '</div>';
  4233. $ret .= '<!DOCTYPE html>';
  4234. $content_type = 'text/html';
  4235. }
  4236. else
  4237. {
  4238. $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
  4239. $content_type = 'application/xhtml+xml';
  4240. }
  4241. $ret .= '<html><head>';
  4242. $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
  4243. $ret .= '</head><body>' . $html . '</body></html>';
  4244. return $ret;
  4245. }
  4246. public function replace_urls($document, $tag, $attributes)
  4247. {
  4248. if (!is_array($attributes))
  4249. {
  4250. $attributes = array($attributes);
  4251. }
  4252. if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
  4253. {
  4254. $elements = $document->getElementsByTagName($tag);
  4255. foreach ($elements as $element)
  4256. {
  4257. foreach ($attributes as $attribute)
  4258. {
  4259. if ($element->hasAttribute($attribute))
  4260. {
  4261. $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
  4262. if ($value !== false)
  4263. {
  4264. $element->setAttribute($attribute, $value);
  4265. }
  4266. }
  4267. }
  4268. }
  4269. }
  4270. }
  4271. public function do_strip_htmltags($match)
  4272. {
  4273. if ($this->encode_instead_of_strip)
  4274. {
  4275. if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
  4276. {
  4277. $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
  4278. $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
  4279. return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
  4280. }
  4281. else
  4282. {
  4283. return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
  4284. }
  4285. }
  4286. elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
  4287. {
  4288. return $match[4];
  4289. }
  4290. else
  4291. {
  4292. return '';
  4293. }
  4294. }
  4295. protected function strip_tag($tag, $document, $type)
  4296. {
  4297. $xpath = new DOMXPath($document);
  4298. $elements = $xpath->query('body//' . $tag);
  4299. if ($this->encode_instead_of_strip)
  4300. {
  4301. foreach ($elements as $element)
  4302. {
  4303. $fragment = $document->createDocumentFragment();
  4304. // For elements which aren't script or style, include the tag itself
  4305. if (!in_array($tag, array('script', 'style')))
  4306. {
  4307. $text = '<' . $tag;
  4308. if ($element->hasAttributes())
  4309. {
  4310. $attrs = array();
  4311. foreach ($element->attributes as $name => $attr)
  4312. {
  4313. $value = $attr->value;
  4314. // In XHTML, empty values should never exist, so we repeat the value
  4315. if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
  4316. {
  4317. $value = $name;
  4318. }
  4319. // For HTML, empty is fine
  4320. elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
  4321. {
  4322. $attrs[] = $name;
  4323. continue;
  4324. }
  4325. // Standard attribute text
  4326. $attrs[] = $name . '="' . $attr->value . '"';
  4327. }
  4328. $text .= ' ' . implode(' ', $attrs);
  4329. }
  4330. $text .= '>';
  4331. $fragment->appendChild(new DOMText($text));
  4332. }
  4333. $number = $element->childNodes->length;
  4334. for ($i = $number; $i > 0; $i--)
  4335. {
  4336. $child = $element->childNodes->item(0);
  4337. $fragment->appendChild($child);
  4338. }
  4339. if (!in_array($tag, array('script', 'style')))
  4340. {
  4341. $fragment->appendChild(new DOMText('</' . $tag . '>'));
  4342. }
  4343. $element->parentNode->replaceChild($fragment, $element);
  4344. }
  4345. return;
  4346. }
  4347. elseif (in_array($tag, array('script', 'style')))
  4348. {
  4349. foreach ($elements as $element)
  4350. {
  4351. $element->parentNode->removeChild($element);
  4352. }
  4353. return;
  4354. }
  4355. else
  4356. {
  4357. foreach ($elements as $element)
  4358. {
  4359. $fragment = $document->createDocumentFragment();
  4360. $number = $element->childNodes->length;
  4361. for ($i = $number; $i > 0; $i--)
  4362. {
  4363. $child = $element->childNodes->item(0);
  4364. $fragment->appendChild($child);
  4365. }
  4366. $element->parentNode->replaceChild($fragment, $element);
  4367. }
  4368. }
  4369. }
  4370. protected function strip_attr($attrib, $document)
  4371. {
  4372. $xpath = new DOMXPath($document);
  4373. $elements = $xpath->query('//*[@' . $attrib . ']');
  4374. foreach ($elements as $element)
  4375. {
  4376. $element->removeAttribute($attrib);
  4377. }
  4378. }
  4379. }
  4380. /**
  4381. * Handles everything related to enclosures (including Media RSS and iTunes RSS)
  4382. *
  4383. * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
  4384. *
  4385. * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
  4386. *
  4387. * @package SimplePie
  4388. * @subpackage API
  4389. */
  4390. class SimplePie_Enclosure
  4391. {
  4392. /**
  4393. * @var string
  4394. * @see get_bitrate()
  4395. */
  4396. var $bitrate;
  4397. /**
  4398. * @var array
  4399. * @see get_captions()
  4400. */
  4401. var $captions;
  4402. /**
  4403. * @var array
  4404. * @see get_categories()
  4405. */
  4406. var $categories;
  4407. /**
  4408. * @var int
  4409. * @see get_channels()
  4410. */
  4411. var $channels;
  4412. /**
  4413. * @var SimplePie_Copyright
  4414. * @see get_copyright()
  4415. */
  4416. var $copyright;
  4417. /**
  4418. * @var array
  4419. * @see get_credits()
  4420. */
  4421. var $credits;
  4422. /**
  4423. * @var string
  4424. * @see get_description()
  4425. */
  4426. var $description;
  4427. /**
  4428. * @var int
  4429. * @see get_duration()
  4430. */
  4431. var $duration;
  4432. /**
  4433. * @var string
  4434. * @see get_expression()
  4435. */
  4436. var $expression;
  4437. /**
  4438. * @var string
  4439. * @see get_framerate()
  4440. */
  4441. var $framerate;
  4442. /**
  4443. * @var string
  4444. * @see get_handler()
  4445. */
  4446. var $handler;
  4447. /**
  4448. * @var array
  4449. * @see get_hashes()
  4450. */
  4451. var $hashes;
  4452. /**
  4453. * @var string
  4454. * @see get_height()
  4455. */
  4456. var $height;
  4457. /**
  4458. * @deprecated
  4459. * @var null
  4460. */
  4461. var $javascript;
  4462. /**
  4463. * @var array
  4464. * @see get_keywords()
  4465. */
  4466. var $keywords;
  4467. /**
  4468. * @var string
  4469. * @see get_language()
  4470. */
  4471. var $lang;
  4472. /**
  4473. * @var string
  4474. * @see get_length()
  4475. */
  4476. var $length;
  4477. /**
  4478. * @var string
  4479. * @see get_link()
  4480. */
  4481. var $link;
  4482. /**
  4483. * @var string
  4484. * @see get_medium()
  4485. */
  4486. var $medium;
  4487. /**
  4488. * @var string
  4489. * @see get_player()
  4490. */
  4491. var $player;
  4492. /**
  4493. * @var array
  4494. * @see get_ratings()
  4495. */
  4496. var $ratings;
  4497. /**
  4498. * @var array
  4499. * @see get_restrictions()
  4500. */
  4501. var $restrictions;
  4502. /**
  4503. * @var string
  4504. * @see get_sampling_rate()
  4505. */
  4506. var $samplingrate;
  4507. /**
  4508. * @var array
  4509. * @see get_thumbnails()
  4510. */
  4511. var $thumbnails;
  4512. /**
  4513. * @var string
  4514. * @see get_title()
  4515. */
  4516. var $title;
  4517. /**
  4518. * @var string
  4519. * @see get_type()
  4520. */
  4521. var $type;
  4522. /**
  4523. * @var string
  4524. * @see get_width()
  4525. */
  4526. var $width;
  4527. /**
  4528. * Constructor, used to input the data
  4529. *
  4530. * For documentation on all the parameters, see the corresponding
  4531. * properties and their accessors
  4532. *
  4533. * @uses idna_convert If available, this will convert an IDN
  4534. */
  4535. 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)
  4536. {
  4537. $this->bitrate = $bitrate;
  4538. $this->captions = $captions;
  4539. $this->categories = $categories;
  4540. $this->channels = $channels;
  4541. $this->copyright = $copyright;
  4542. $this->credits = $credits;
  4543. $this->description = $description;
  4544. $this->duration = $duration;
  4545. $this->expression = $expression;
  4546. $this->framerate = $framerate;
  4547. $this->hashes = $hashes;
  4548. $this->height = $height;
  4549. $this->keywords = $keywords;
  4550. $this->lang = $lang;
  4551. $this->length = $length;
  4552. $this->link = $link;
  4553. $this->medium = $medium;
  4554. $this->player = $player;
  4555. $this->ratings = $ratings;
  4556. $this->restrictions = $restrictions;
  4557. $this->samplingrate = $samplingrate;
  4558. $this->thumbnails = $thumbnails;
  4559. $this->title = $title;
  4560. $this->type = $type;
  4561. $this->width = $width;
  4562. if (class_exists('idna_convert'))
  4563. {
  4564. $idn = new idna_convert();
  4565. $parsed = SimplePie_Misc::parse_url($link);
  4566. $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
  4567. }
  4568. $this->handler = $this->get_handler(); // Needs to load last
  4569. }
  4570. /**
  4571. * String-ified version
  4572. *
  4573. * @return string
  4574. */
  4575. public function __toString()
  4576. {
  4577. // There is no $this->data here
  4578. return md5(serialize($this));
  4579. }
  4580. /**
  4581. * Get the bitrate
  4582. *
  4583. * @return string|null
  4584. */
  4585. public function get_bitrate()
  4586. {
  4587. if ($this->bitrate !== null)
  4588. {
  4589. return $this->bitrate;
  4590. }
  4591. else
  4592. {
  4593. return null;
  4594. }
  4595. }
  4596. /**
  4597. * Get a single caption
  4598. *
  4599. * @param int $key
  4600. * @return SimplePie_Caption|null
  4601. */
  4602. public function get_caption($key = 0)
  4603. {
  4604. $captions = $this->get_captions();
  4605. if (isset($captions[$key]))
  4606. {
  4607. return $captions[$key];
  4608. }
  4609. else
  4610. {
  4611. return null;
  4612. }
  4613. }
  4614. /**
  4615. * Get all captions
  4616. *
  4617. * @return array|null Array of {@see SimplePie_Caption} objects
  4618. */
  4619. public function get_captions()
  4620. {
  4621. if ($this->captions !== null)
  4622. {
  4623. return $this->captions;
  4624. }
  4625. else
  4626. {
  4627. return null;
  4628. }
  4629. }
  4630. /**
  4631. * Get a single category
  4632. *
  4633. * @param int $key
  4634. * @return SimplePie_Category|null
  4635. */
  4636. public function get_category($key = 0)
  4637. {
  4638. $categories = $this->get_categories();
  4639. if (isset($categories[$key]))
  4640. {
  4641. return $categories[$key];
  4642. }
  4643. else
  4644. {
  4645. return null;
  4646. }
  4647. }
  4648. /**
  4649. * Get all categories
  4650. *
  4651. * @return array|null Array of {@see SimplePie_Category} objects
  4652. */
  4653. public function get_categories()
  4654. {
  4655. if ($this->categories !== null)
  4656. {
  4657. return $this->categories;
  4658. }
  4659. else
  4660. {
  4661. return null;
  4662. }
  4663. }
  4664. /**
  4665. * Get the number of audio channels
  4666. *
  4667. * @return int|null
  4668. */
  4669. public function get_channels()
  4670. {
  4671. if ($this->channels !== null)
  4672. {
  4673. return $this->channels;
  4674. }
  4675. else
  4676. {
  4677. return null;
  4678. }
  4679. }
  4680. /**
  4681. * Get the copyright information
  4682. *
  4683. * @return SimplePie_Copyright|null
  4684. */
  4685. public function get_copyright()
  4686. {
  4687. if ($this->copyright !== null)
  4688. {
  4689. return $this->copyright;
  4690. }
  4691. else
  4692. {
  4693. return null;
  4694. }
  4695. }
  4696. /**
  4697. * Get a single credit
  4698. *
  4699. * @param int $key
  4700. * @return SimplePie_Credit|null
  4701. */
  4702. public function get_credit($key = 0)
  4703. {
  4704. $credits = $this->get_credits();
  4705. if (isset($credits[$key]))
  4706. {
  4707. return $credits[$key];
  4708. }
  4709. else
  4710. {
  4711. return null;
  4712. }
  4713. }
  4714. /**
  4715. * Get all credits
  4716. *
  4717. * @return array|null Array of {@see SimplePie_Credit} objects
  4718. */
  4719. public function get_credits()
  4720. {
  4721. if ($this->credits !== null)
  4722. {
  4723. return $this->credits;
  4724. }
  4725. else
  4726. {
  4727. return null;
  4728. }
  4729. }
  4730. /**
  4731. * Get the description of the enclosure
  4732. *
  4733. * @return string|null
  4734. */
  4735. public function get_description()
  4736. {
  4737. if ($this->description !== null)
  4738. {
  4739. return $this->description;
  4740. }
  4741. else
  4742. {
  4743. return null;
  4744. }
  4745. }
  4746. /**
  4747. * Get the duration of the enclosure
  4748. *
  4749. * @param string $convert Convert seconds into hh:mm:ss
  4750. * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
  4751. */
  4752. public function get_duration($convert = false)
  4753. {
  4754. if ($this->duration !== null)
  4755. {
  4756. if ($convert)
  4757. {
  4758. $time = SimplePie_Misc::time_hms($this->duration);
  4759. return $time;
  4760. }
  4761. else
  4762. {
  4763. return $this->duration;
  4764. }
  4765. }
  4766. else
  4767. {
  4768. return null;
  4769. }
  4770. }
  4771. /**
  4772. * Get the expression
  4773. *
  4774. * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
  4775. */
  4776. public function get_expression()
  4777. {
  4778. if ($this->expression !== null)
  4779. {
  4780. return $this->expression;
  4781. }
  4782. else
  4783. {
  4784. return 'full';
  4785. }
  4786. }
  4787. /**
  4788. * Get the file extension
  4789. *
  4790. * @return string|null
  4791. */
  4792. public function get_extension()
  4793. {
  4794. if ($this->link !== null)
  4795. {
  4796. $url = SimplePie_Misc::parse_url($this->link);
  4797. if ($url['path'] !== '')
  4798. {
  4799. return pathinfo($url['path'], PATHINFO_EXTENSION);
  4800. }
  4801. }
  4802. return null;
  4803. }
  4804. /**
  4805. * Get the framerate (in frames-per-second)
  4806. *
  4807. * @return string|null
  4808. */
  4809. public function get_framerate()
  4810. {
  4811. if ($this->framerate !== null)
  4812. {
  4813. return $this->framerate;
  4814. }
  4815. else
  4816. {
  4817. return null;
  4818. }
  4819. }
  4820. /**
  4821. * Get the preferred handler
  4822. *
  4823. * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
  4824. */
  4825. public function get_handler()
  4826. {
  4827. return $this->get_real_type(true);
  4828. }
  4829. /**
  4830. * Get a single hash
  4831. *
  4832. * @link http://www.rssboard.org/media-rss#media-hash
  4833. * @param int $key
  4834. * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
  4835. */
  4836. public function get_hash($key = 0)
  4837. {
  4838. $hashes = $this->get_hashes();
  4839. if (isset($hashes[$key]))
  4840. {
  4841. return $hashes[$key];
  4842. }
  4843. else
  4844. {
  4845. return null;
  4846. }
  4847. }
  4848. /**
  4849. * Get all credits
  4850. *
  4851. * @return array|null Array of strings, see {@see get_hash()}
  4852. */
  4853. public function get_hashes()
  4854. {
  4855. if ($this->hashes !== null)
  4856. {
  4857. return $this->hashes;
  4858. }
  4859. else
  4860. {
  4861. return null;
  4862. }
  4863. }
  4864. /**
  4865. * Get the height
  4866. *
  4867. * @return string|null
  4868. */
  4869. public function get_height()
  4870. {
  4871. if ($this->height !== null)
  4872. {
  4873. return $this->height;
  4874. }
  4875. else
  4876. {
  4877. return null;
  4878. }
  4879. }
  4880. /**
  4881. * Get the language
  4882. *
  4883. * @link http://tools.ietf.org/html/rfc3066
  4884. * @return string|null Language code as per RFC 3066
  4885. */
  4886. public function get_language()
  4887. {
  4888. if ($this->lang !== null)
  4889. {
  4890. return $this->lang;
  4891. }
  4892. else
  4893. {
  4894. return null;
  4895. }
  4896. }
  4897. /**
  4898. * Get a single keyword
  4899. *
  4900. * @param int $key
  4901. * @return string|null
  4902. */
  4903. public function get_keyword($key = 0)
  4904. {
  4905. $keywords = $this->get_keywords();
  4906. if (isset($keywords[$key]))
  4907. {
  4908. return $keywords[$key];
  4909. }
  4910. else
  4911. {
  4912. return null;
  4913. }
  4914. }
  4915. /**
  4916. * Get all keywords
  4917. *
  4918. * @return array|null Array of strings
  4919. */
  4920. public function get_keywords()
  4921. {
  4922. if ($this->keywords !== null)
  4923. {
  4924. return $this->keywords;
  4925. }
  4926. else
  4927. {
  4928. return null;
  4929. }
  4930. }
  4931. /**
  4932. * Get length
  4933. *
  4934. * @return float Length in bytes
  4935. */
  4936. public function get_length()
  4937. {
  4938. if ($this->length !== null)
  4939. {
  4940. return $this->length;
  4941. }
  4942. else
  4943. {
  4944. return null;
  4945. }
  4946. }
  4947. /**
  4948. * Get the URL
  4949. *
  4950. * @return string|null
  4951. */
  4952. public function get_link()
  4953. {
  4954. if ($this->link !== null)
  4955. {
  4956. return urldecode($this->link);
  4957. }
  4958. else
  4959. {
  4960. return null;
  4961. }
  4962. }
  4963. /**
  4964. * Get the medium
  4965. *
  4966. * @link http://www.rssboard.org/media-rss#media-content
  4967. * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
  4968. */
  4969. public function get_medium()
  4970. {
  4971. if ($this->medium !== null)
  4972. {
  4973. return $this->medium;
  4974. }
  4975. else
  4976. {
  4977. return null;
  4978. }
  4979. }
  4980. /**
  4981. * Get the player URL
  4982. *
  4983. * Typically the same as {@see get_permalink()}
  4984. * @return string|null Player URL
  4985. */
  4986. public function get_player()
  4987. {
  4988. if ($this->player !== null)
  4989. {
  4990. return $this->player;
  4991. }
  4992. else
  4993. {
  4994. return null;
  4995. }
  4996. }
  4997. /**
  4998. * Get a single rating
  4999. *
  5000. * @param int $key
  5001. * @return SimplePie_Rating|null
  5002. */
  5003. public function get_rating($key = 0)
  5004. {
  5005. $ratings = $this->get_ratings();
  5006. if (isset($ratings[$key]))
  5007. {
  5008. return $ratings[$key];
  5009. }
  5010. else
  5011. {
  5012. return null;
  5013. }
  5014. }
  5015. /**
  5016. * Get all ratings
  5017. *
  5018. * @return array|null Array of {@see SimplePie_Rating} objects
  5019. */
  5020. public function get_ratings()
  5021. {
  5022. if ($this->ratings !== null)
  5023. {
  5024. return $this->ratings;
  5025. }
  5026. else
  5027. {
  5028. return null;
  5029. }
  5030. }
  5031. /**
  5032. * Get a single restriction
  5033. *
  5034. * @param int $key
  5035. * @return SimplePie_Restriction|null
  5036. */
  5037. public function get_restriction($key = 0)
  5038. {
  5039. $restrictions = $this->get_restrictions();
  5040. if (isset($restrictions[$key]))
  5041. {
  5042. return $restrictions[$key];
  5043. }
  5044. else
  5045. {
  5046. return null;
  5047. }
  5048. }
  5049. /**
  5050. * Get all restrictions
  5051. *
  5052. * @return array|null Array of {@see SimplePie_Restriction} objects
  5053. */
  5054. public function get_restrictions()
  5055. {
  5056. if ($this->restrictions !== null)
  5057. {
  5058. return $this->restrictions;
  5059. }
  5060. else
  5061. {
  5062. return null;
  5063. }
  5064. }
  5065. /**
  5066. * Get the sampling rate (in kHz)
  5067. *
  5068. * @return string|null
  5069. */
  5070. public function get_sampling_rate()
  5071. {
  5072. if ($this->samplingrate !== null)
  5073. {
  5074. return $this->samplingrate;
  5075. }
  5076. else
  5077. {
  5078. return null;
  5079. }
  5080. }
  5081. /**
  5082. * Get the file size (in MiB)
  5083. *
  5084. * @return float|null File size in mebibytes (1048 bytes)
  5085. */
  5086. public function get_size()
  5087. {
  5088. $length = $this->get_length();
  5089. if ($length !== null)
  5090. {
  5091. return round($length/1048576, 2);
  5092. }
  5093. else
  5094. {
  5095. return null;
  5096. }
  5097. }
  5098. /**
  5099. * Get a single thumbnail
  5100. *
  5101. * @param int $key
  5102. * @return string|null Thumbnail URL
  5103. */
  5104. public function get_thumbnail($key = 0)
  5105. {
  5106. $thumbnails = $this->get_thumbnails();
  5107. if (isset($thumbnails[$key]))
  5108. {
  5109. return $thumbnails[$key];
  5110. }
  5111. else
  5112. {
  5113. return null;
  5114. }
  5115. }
  5116. /**
  5117. * Get all thumbnails
  5118. *
  5119. * @return array|null Array of thumbnail URLs
  5120. */
  5121. public function get_thumbnails()
  5122. {
  5123. if ($this->thumbnails !== null)
  5124. {
  5125. return $this->thumbnails;
  5126. }
  5127. else
  5128. {
  5129. return null;
  5130. }
  5131. }
  5132. /**
  5133. * Get the title
  5134. *
  5135. * @return string|null
  5136. */
  5137. public function get_title()
  5138. {
  5139. if ($this->title !== null)
  5140. {
  5141. return $this->title;
  5142. }
  5143. else
  5144. {
  5145. return null;
  5146. }
  5147. }
  5148. /**
  5149. * Get mimetype of the enclosure
  5150. *
  5151. * @see get_real_type()
  5152. * @return string|null MIME type
  5153. */
  5154. public function get_type()
  5155. {
  5156. if ($this->type !== null)
  5157. {
  5158. return $this->type;
  5159. }
  5160. else
  5161. {
  5162. return null;
  5163. }
  5164. }
  5165. /**
  5166. * Get the width
  5167. *
  5168. * @return string|null
  5169. */
  5170. public function get_width()
  5171. {
  5172. if ($this->width !== null)
  5173. {
  5174. return $this->width;
  5175. }
  5176. else
  5177. {
  5178. return null;
  5179. }
  5180. }
  5181. /**
  5182. * Embed the enclosure using `<embed>`
  5183. *
  5184. * @deprecated Use the second parameter to {@see embed} instead
  5185. *
  5186. * @param array|string $options See first paramter to {@see embed}
  5187. * @return string HTML string to output
  5188. */
  5189. public function native_embed($options='')
  5190. {
  5191. return $this->embed($options, true);
  5192. }
  5193. /**
  5194. * Embed the enclosure using Javascript
  5195. *
  5196. * `$options` is an array or comma-separated key:value string, with the
  5197. * following properties:
  5198. *
  5199. * - `alt` (string): Alternate content for when an end-user does not have
  5200. * the appropriate handler installed or when a file type is
  5201. * unsupported. Can be any text or HTML. Defaults to blank.
  5202. * - `altclass` (string): If a file type is unsupported, the end-user will
  5203. * see the alt text (above) linked directly to the content. That link
  5204. * will have this value as its class name. Defaults to blank.
  5205. * - `audio` (string): This is an image that should be used as a
  5206. * placeholder for audio files before they're loaded (QuickTime-only).
  5207. * Can be any relative or absolute URL. Defaults to blank.
  5208. * - `bgcolor` (string): The background color for the media, if not
  5209. * already transparent. Defaults to `#ffffff`.
  5210. * - `height` (integer): The height of the embedded media. Accepts any
  5211. * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
  5212. * and it is recommended that you use this default.
  5213. * - `loop` (boolean): Do you want the media to loop when it's done?
  5214. * Defaults to `false`.
  5215. * - `mediaplayer` (string): The location of the included
  5216. * `mediaplayer.swf` file. This allows for the playback of Flash Video
  5217. * (`.flv`) files, and is the default handler for non-Odeo MP3's.
  5218. * Defaults to blank.
  5219. * - `video` (string): This is an image that should be used as a
  5220. * placeholder for video files before they're loaded (QuickTime-only).
  5221. * Can be any relative or absolute URL. Defaults to blank.
  5222. * - `width` (integer): The width of the embedded media. Accepts any
  5223. * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
  5224. * and it is recommended that you use this default.
  5225. * - `widescreen` (boolean): Is the enclosure widescreen or standard?
  5226. * This applies only to video enclosures, and will automatically resize
  5227. * the content appropriately. Defaults to `false`, implying 4:3 mode.
  5228. *
  5229. * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
  5230. * will default to 480x360 video resolution. Widescreen (16:9) mode with
  5231. * `width` and `height` set to `auto` will default to 480x270 video resolution.
  5232. *
  5233. * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
  5234. * @param array|string $options Comma-separated key:value list, or array
  5235. * @param bool $native Use `<embed>`
  5236. * @return string HTML string to output
  5237. */
  5238. public function embed($options = '', $native = false)
  5239. {
  5240. // Set up defaults
  5241. $audio = '';
  5242. $video = '';
  5243. $alt = '';
  5244. $altclass = '';
  5245. $loop = 'false';
  5246. $width = 'auto';
  5247. $height = 'auto';
  5248. $bgcolor = '#ffffff';
  5249. $mediaplayer = '';
  5250. $widescreen = false;
  5251. $handler = $this->get_handler();
  5252. $type = $this->get_real_type();
  5253. // Process options and reassign values as necessary
  5254. if (is_array($options))
  5255. {
  5256. extract($options);
  5257. }
  5258. else
  5259. {
  5260. $options = explode(',', $options);
  5261. foreach($options as $option)
  5262. {
  5263. $opt = explode(':', $option, 2);
  5264. if (isset($opt[0], $opt[1]))
  5265. {
  5266. $opt[0] = trim($opt[0]);
  5267. $opt[1] = trim($opt[1]);
  5268. switch ($opt[0])
  5269. {
  5270. case 'audio':
  5271. $audio = $opt[1];
  5272. break;
  5273. case 'video':
  5274. $video = $opt[1];
  5275. break;
  5276. case 'alt':
  5277. $alt = $opt[1];
  5278. break;
  5279. case 'altclass':
  5280. $altclass = $opt[1];
  5281. break;
  5282. case 'loop':
  5283. $loop = $opt[1];
  5284. break;
  5285. case 'width':
  5286. $width = $opt[1];
  5287. break;
  5288. case 'height':
  5289. $height = $opt[1];
  5290. break;
  5291. case 'bgcolor':
  5292. $bgcolor = $opt[1];
  5293. break;
  5294. case 'mediaplayer':
  5295. $mediaplayer = $opt[1];
  5296. break;
  5297. case 'widescreen':
  5298. $widescreen = $opt[1];
  5299. break;
  5300. }
  5301. }
  5302. }
  5303. }
  5304. $mime = explode('/', $type, 2);
  5305. $mime = $mime[0];
  5306. // Process values for 'auto'
  5307. if ($width === 'auto')
  5308. {
  5309. if ($mime === 'video')
  5310. {
  5311. if ($height === 'auto')
  5312. {
  5313. $width = 480;
  5314. }
  5315. elseif ($widescreen)
  5316. {
  5317. $width = round((intval($height)/9)*16);
  5318. }
  5319. else
  5320. {
  5321. $width = round((intval($height)/3)*4);
  5322. }
  5323. }
  5324. else
  5325. {
  5326. $width = '100%';
  5327. }
  5328. }
  5329. if ($height === 'auto')
  5330. {
  5331. if ($mime === 'audio')
  5332. {
  5333. $height = 0;
  5334. }
  5335. elseif ($mime === 'video')
  5336. {
  5337. if ($width === 'auto')
  5338. {
  5339. if ($widescreen)
  5340. {
  5341. $height = 270;
  5342. }
  5343. else
  5344. {
  5345. $height = 360;
  5346. }
  5347. }
  5348. elseif ($widescreen)
  5349. {
  5350. $height = round((intval($width)/16)*9);
  5351. }
  5352. else
  5353. {
  5354. $height = round((intval($width)/4)*3);
  5355. }
  5356. }
  5357. else
  5358. {
  5359. $height = 376;
  5360. }
  5361. }
  5362. elseif ($mime === 'audio')
  5363. {
  5364. $height = 0;
  5365. }
  5366. // Set proper placeholder value
  5367. if ($mime === 'audio')
  5368. {
  5369. $placeholder = $audio;
  5370. }
  5371. elseif ($mime === 'video')
  5372. {
  5373. $placeholder = $video;
  5374. }
  5375. $embed = '';
  5376. // Flash
  5377. if ($handler === 'flash')
  5378. {
  5379. if ($native)
  5380. {
  5381. $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>";
  5382. }
  5383. else
  5384. {
  5385. $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
  5386. }
  5387. }
  5388. // Flash Media Player file types.
  5389. // Preferred handler for MP3 file types.
  5390. elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
  5391. {
  5392. $height += 20;
  5393. if ($native)
  5394. {
  5395. $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>";
  5396. }
  5397. else
  5398. {
  5399. $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
  5400. }
  5401. }
  5402. // QuickTime 7 file types. Need to test with QuickTime 6.
  5403. // Only handle MP3's if the Flash Media Player is not present.
  5404. elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
  5405. {
  5406. $height += 16;
  5407. if ($native)
  5408. {
  5409. if ($placeholder !== '')
  5410. {
  5411. $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>";
  5412. }
  5413. else
  5414. {
  5415. $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>";
  5416. }
  5417. }
  5418. else
  5419. {
  5420. $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
  5421. }
  5422. }
  5423. // Windows Media
  5424. elseif ($handler === 'wmedia')
  5425. {
  5426. $height += 45;
  5427. if ($native)
  5428. {
  5429. $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>";
  5430. }
  5431. else
  5432. {
  5433. $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
  5434. }
  5435. }
  5436. // Everything else
  5437. else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
  5438. return $embed;
  5439. }
  5440. /**
  5441. * Get the real media type
  5442. *
  5443. * Often, feeds lie to us, necessitating a bit of deeper inspection. This
  5444. * converts types to their canonical representations based on the file
  5445. * extension
  5446. *
  5447. * @see get_type()
  5448. * @param bool $find_handler Internal use only, use {@see get_handler()} instead
  5449. * @return string MIME type
  5450. */
  5451. public function get_real_type($find_handler = false)
  5452. {
  5453. // Mime-types by handler.
  5454. $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
  5455. $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
  5456. $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
  5457. $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
  5458. $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
  5459. if ($this->get_type() !== null)
  5460. {
  5461. $type = strtolower($this->type);
  5462. }
  5463. else
  5464. {
  5465. $type = null;
  5466. }
  5467. // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
  5468. if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
  5469. {
  5470. switch (strtolower($this->get_extension()))
  5471. {
  5472. // Audio mime-types
  5473. case 'aac':
  5474. case 'adts':
  5475. $type = 'audio/acc';
  5476. break;
  5477. case 'aif':
  5478. case 'aifc':
  5479. case 'aiff':
  5480. case 'cdda':
  5481. $type = 'audio/aiff';
  5482. break;
  5483. case 'bwf':
  5484. $type = 'audio/wav';
  5485. break;
  5486. case 'kar':
  5487. case 'mid':
  5488. case 'midi':
  5489. case 'smf':
  5490. $type = 'audio/midi';
  5491. break;
  5492. case 'm4a':
  5493. $type = 'audio/x-m4a';
  5494. break;
  5495. case 'mp3':
  5496. case 'swa':
  5497. $type = 'audio/mp3';
  5498. break;
  5499. case 'wav':
  5500. $type = 'audio/wav';
  5501. break;
  5502. case 'wax':
  5503. $type = 'audio/x-ms-wax';
  5504. break;
  5505. case 'wma':
  5506. $type = 'audio/x-ms-wma';
  5507. break;
  5508. // Video mime-types
  5509. case '3gp':
  5510. case '3gpp':
  5511. $type = 'video/3gpp';
  5512. break;
  5513. case '3g2':
  5514. case '3gp2':
  5515. $type = 'video/3gpp2';
  5516. break;
  5517. case 'asf':
  5518. $type = 'video/x-ms-asf';
  5519. break;
  5520. case 'flv':
  5521. $type = 'video/x-flv';
  5522. break;
  5523. case 'm1a':
  5524. case 'm1s':
  5525. case 'm1v':
  5526. case 'm15':
  5527. case 'm75':
  5528. case 'mp2':
  5529. case 'mpa':
  5530. case 'mpeg':
  5531. case 'mpg':
  5532. case 'mpm':
  5533. case 'mpv':
  5534. $type = 'video/mpeg';
  5535. break;
  5536. case 'm4v':
  5537. $type = 'video/x-m4v';
  5538. break;
  5539. case 'mov':
  5540. case 'qt':
  5541. $type = 'video/quicktime';
  5542. break;
  5543. case 'mp4':
  5544. case 'mpg4':
  5545. $type = 'video/mp4';
  5546. break;
  5547. case 'sdv':
  5548. $type = 'video/sd-video';
  5549. break;
  5550. case 'wm':
  5551. $type = 'video/x-ms-wm';
  5552. break;
  5553. case 'wmv':
  5554. $type = 'video/x-ms-wmv';
  5555. break;
  5556. case 'wvx':
  5557. $type = 'video/x-ms-wvx';
  5558. break;
  5559. // Flash mime-types
  5560. case 'spl':
  5561. $type = 'application/futuresplash';
  5562. break;
  5563. case 'swf':
  5564. $type = 'application/x-shockwave-flash';
  5565. break;
  5566. }
  5567. }
  5568. if ($find_handler)
  5569. {
  5570. if (in_array($type, $types_flash))
  5571. {
  5572. return 'flash';
  5573. }
  5574. elseif (in_array($type, $types_fmedia))
  5575. {
  5576. return 'fmedia';
  5577. }
  5578. elseif (in_array($type, $types_quicktime))
  5579. {
  5580. return 'quicktime';
  5581. }
  5582. elseif (in_array($type, $types_wmedia))
  5583. {
  5584. return 'wmedia';
  5585. }
  5586. elseif (in_array($type, $types_mp3))
  5587. {
  5588. return 'mp3';
  5589. }
  5590. else
  5591. {
  5592. return null;
  5593. }
  5594. }
  5595. else
  5596. {
  5597. return $type;
  5598. }
  5599. }
  5600. }
  5601. /**
  5602. * Parses the XML Declaration
  5603. *
  5604. * @package SimplePie
  5605. * @subpackage Parsing
  5606. */
  5607. class SimplePie_XML_Declaration_Parser
  5608. {
  5609. /**
  5610. * XML Version
  5611. *
  5612. * @access public
  5613. * @var string
  5614. */
  5615. var $version = '1.0';
  5616. /**
  5617. * Encoding
  5618. *
  5619. * @access public
  5620. * @var string
  5621. */
  5622. var $encoding = 'UTF-8';
  5623. /**
  5624. * Standalone
  5625. *
  5626. * @access public
  5627. * @var bool
  5628. */
  5629. var $standalone = false;
  5630. /**
  5631. * Current state of the state machine
  5632. *
  5633. * @access private
  5634. * @var string
  5635. */
  5636. var $state = 'before_version_name';
  5637. /**
  5638. * Input data
  5639. *
  5640. * @access private
  5641. * @var string
  5642. */
  5643. var $data = '';
  5644. /**
  5645. * Input data length (to avoid calling strlen() everytime this is needed)
  5646. *
  5647. * @access private
  5648. * @var int
  5649. */
  5650. var $data_length = 0;
  5651. /**
  5652. * Current position of the pointer
  5653. *
  5654. * @var int
  5655. * @access private
  5656. */
  5657. var $position = 0;
  5658. /**
  5659. * Create an instance of the class with the input data
  5660. *
  5661. * @access public
  5662. * @param string $data Input data
  5663. */
  5664. public function __construct($data)
  5665. {
  5666. $this->data = $data;
  5667. $this->data_length = strlen($this->data);
  5668. }
  5669. /**
  5670. * Parse the input data
  5671. *
  5672. * @access public
  5673. * @return bool true on success, false on failure
  5674. */
  5675. public function parse()
  5676. {
  5677. while ($this->state && $this->state !== 'emit' && $this->has_data())
  5678. {
  5679. $state = $this->state;
  5680. $this->$state();
  5681. }
  5682. $this->data = '';
  5683. if ($this->state === 'emit')
  5684. {
  5685. return true;
  5686. }
  5687. else
  5688. {
  5689. $this->version = '';
  5690. $this->encoding = '';
  5691. $this->standalone = '';
  5692. return false;
  5693. }
  5694. }
  5695. /**
  5696. * Check whether there is data beyond the pointer
  5697. *
  5698. * @access private
  5699. * @return bool true if there is further data, false if not
  5700. */
  5701. public function has_data()
  5702. {
  5703. return (bool) ($this->position < $this->data_length);
  5704. }
  5705. /**
  5706. * Advance past any whitespace
  5707. *
  5708. * @return int Number of whitespace characters passed
  5709. */
  5710. public function skip_whitespace()
  5711. {
  5712. $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
  5713. $this->position += $whitespace;
  5714. return $whitespace;
  5715. }
  5716. /**
  5717. * Read value
  5718. */
  5719. public function get_value()
  5720. {
  5721. $quote = substr($this->data, $this->position, 1);
  5722. if ($quote === '"' || $quote === "'")
  5723. {
  5724. $this->position++;
  5725. $len = strcspn($this->data, $quote, $this->position);
  5726. if ($this->has_data())
  5727. {
  5728. $value = substr($this->data, $this->position, $len);
  5729. $this->position += $len + 1;
  5730. return $value;
  5731. }
  5732. }
  5733. return false;
  5734. }
  5735. public function before_version_name()
  5736. {
  5737. if ($this->skip_whitespace())
  5738. {
  5739. $this->state = 'version_name';
  5740. }
  5741. else
  5742. {
  5743. $this->state = false;
  5744. }
  5745. }
  5746. public function version_name()
  5747. {
  5748. if (substr($this->data, $this->position, 7) === 'version')
  5749. {
  5750. $this->position += 7;
  5751. $this->skip_whitespace();
  5752. $this->state = 'version_equals';
  5753. }
  5754. else
  5755. {
  5756. $this->state = false;
  5757. }
  5758. }
  5759. public function version_equals()
  5760. {
  5761. if (substr($this->data, $this->position, 1) === '=')
  5762. {
  5763. $this->position++;
  5764. $this->skip_whitespace();
  5765. $this->state = 'version_value';
  5766. }
  5767. else
  5768. {
  5769. $this->state = false;
  5770. }
  5771. }
  5772. public function version_value()
  5773. {
  5774. if ($this->version = $this->get_value())
  5775. {
  5776. $this->skip_whitespace();
  5777. if ($this->has_data())
  5778. {
  5779. $this->state = 'encoding_name';
  5780. }
  5781. else
  5782. {
  5783. $this->state = 'emit';
  5784. }
  5785. }
  5786. else
  5787. {
  5788. $this->state = false;
  5789. }
  5790. }
  5791. public function encoding_name()
  5792. {
  5793. if (substr($this->data, $this->position, 8) === 'encoding')
  5794. {
  5795. $this->position += 8;
  5796. $this->skip_whitespace();
  5797. $this->state = 'encoding_equals';
  5798. }
  5799. else
  5800. {
  5801. $this->state = 'standalone_name';
  5802. }
  5803. }
  5804. public function encoding_equals()
  5805. {
  5806. if (substr($this->data, $this->position, 1) === '=')
  5807. {
  5808. $this->position++;
  5809. $this->skip_whitespace();
  5810. $this->state = 'encoding_value';
  5811. }
  5812. else
  5813. {
  5814. $this->state = false;
  5815. }
  5816. }
  5817. public function encoding_value()
  5818. {
  5819. if ($this->encoding = $this->get_value())
  5820. {
  5821. $this->skip_whitespace();
  5822. if ($this->has_data())
  5823. {
  5824. $this->state = 'standalone_name';
  5825. }
  5826. else
  5827. {
  5828. $this->state = 'emit';
  5829. }
  5830. }
  5831. else
  5832. {
  5833. $this->state = false;
  5834. }
  5835. }
  5836. public function standalone_name()
  5837. {
  5838. if (substr($this->data, $this->position, 10) === 'standalone')
  5839. {
  5840. $this->position += 10;
  5841. $this->skip_whitespace();
  5842. $this->state = 'standalone_equals';
  5843. }
  5844. else
  5845. {
  5846. $this->state = false;
  5847. }
  5848. }
  5849. public function standalone_equals()
  5850. {
  5851. if (substr($this->data, $this->position, 1) === '=')
  5852. {
  5853. $this->position++;
  5854. $this->skip_whitespace();
  5855. $this->state = 'standalone_value';
  5856. }
  5857. else
  5858. {
  5859. $this->state = false;
  5860. }
  5861. }
  5862. public function standalone_value()
  5863. {
  5864. if ($standalone = $this->get_value())
  5865. {
  5866. switch ($standalone)
  5867. {
  5868. case 'yes':
  5869. $this->standalone = true;
  5870. break;
  5871. case 'no':
  5872. $this->standalone = false;
  5873. break;
  5874. default:
  5875. $this->state = false;
  5876. return;
  5877. }
  5878. $this->skip_whitespace();
  5879. if ($this->has_data())
  5880. {
  5881. $this->state = false;
  5882. }
  5883. else
  5884. {
  5885. $this->state = 'emit';
  5886. }
  5887. }
  5888. else
  5889. {
  5890. $this->state = false;
  5891. }
  5892. }
  5893. }
  5894. /**
  5895. * Used for fetching remote files and reading local files
  5896. *
  5897. * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
  5898. *
  5899. * This class can be overloaded with {@see SimplePie::set_file_class()}
  5900. *
  5901. * @package SimplePie
  5902. * @subpackage HTTP
  5903. * @todo Move to properly supporting RFC2616 (HTTP/1.1)
  5904. */
  5905. class SimplePie_File
  5906. {
  5907. var $url;
  5908. var $useragent;
  5909. var $success = true;
  5910. var $headers = array();
  5911. var $body;
  5912. var $status_code;
  5913. var $redirects = 0;
  5914. var $error;
  5915. var $method = SIMPLEPIE_FILE_SOURCE_NONE;
  5916. public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
  5917. {
  5918. if (class_exists('idna_convert'))
  5919. {
  5920. $idn = new idna_convert();
  5921. $parsed = SimplePie_Misc::parse_url($url);
  5922. $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
  5923. }
  5924. $this->url = $url;
  5925. $this->useragent = $useragent;
  5926. if (preg_match('/^http(s)?:\/\//i', $url))
  5927. {
  5928. if ($useragent === null)
  5929. {
  5930. $useragent = ini_get('user_agent');
  5931. $this->useragent = $useragent;
  5932. }
  5933. if (!is_array($headers))
  5934. {
  5935. $headers = array();
  5936. }
  5937. if (!$force_fsockopen && function_exists('curl_exec'))
  5938. {
  5939. $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
  5940. $fp = curl_init();
  5941. $headers2 = array();
  5942. foreach ($headers as $key => $value)
  5943. {
  5944. $headers2[] = "$key: $value";
  5945. }
  5946. if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
  5947. {
  5948. curl_setopt($fp, CURLOPT_ENCODING, '');
  5949. }
  5950. curl_setopt($fp, CURLOPT_URL, $url);
  5951. curl_setopt($fp, CURLOPT_HEADER, 1);
  5952. curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
  5953. curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
  5954. curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
  5955. curl_setopt($fp, CURLOPT_REFERER, $url);
  5956. curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
  5957. curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
  5958. if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
  5959. {
  5960. curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
  5961. curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
  5962. }
  5963. $this->headers = curl_exec($fp);
  5964. if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
  5965. {
  5966. curl_setopt($fp, CURLOPT_ENCODING, 'none');
  5967. $this->headers = curl_exec($fp);
  5968. }
  5969. if (curl_errno($fp))
  5970. {
  5971. $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
  5972. $this->success = false;
  5973. }
  5974. else
  5975. {
  5976. $info = curl_getinfo($fp);
  5977. curl_close($fp);
  5978. $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
  5979. $this->headers = array_pop($this->headers);
  5980. $parser = new SimplePie_HTTP_Parser($this->headers);
  5981. if ($parser->parse())
  5982. {
  5983. $this->headers = $parser->headers;
  5984. $this->body = $parser->body;
  5985. $this->status_code = $parser->status_code;
  5986. 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)
  5987. {
  5988. $this->redirects++;
  5989. $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
  5990. return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
  5991. }
  5992. }
  5993. }
  5994. }
  5995. else
  5996. {
  5997. $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
  5998. $url_parts = parse_url($url);
  5999. $socket_host = $url_parts['host'];
  6000. if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
  6001. {
  6002. $socket_host = "ssl://$url_parts[host]";
  6003. $url_parts['port'] = 443;
  6004. }
  6005. if (!isset($url_parts['port']))
  6006. {
  6007. $url_parts['port'] = 80;
  6008. }
  6009. $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
  6010. if (!$fp)
  6011. {
  6012. $this->error = 'fsockopen error: ' . $errstr;
  6013. $this->success = false;
  6014. }
  6015. else
  6016. {
  6017. stream_set_timeout($fp, $timeout);
  6018. if (isset($url_parts['path']))
  6019. {
  6020. if (isset($url_parts['query']))
  6021. {
  6022. $get = "$url_parts[path]?$url_parts[query]";
  6023. }
  6024. else
  6025. {
  6026. $get = $url_parts['path'];
  6027. }
  6028. }
  6029. else
  6030. {
  6031. $get = '/';
  6032. }
  6033. $out = "GET $get HTTP/1.1\r\n";
  6034. $out .= "Host: $url_parts[host]\r\n";
  6035. $out .= "User-Agent: $useragent\r\n";
  6036. if (extension_loaded('zlib'))
  6037. {
  6038. $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
  6039. }
  6040. if (isset($url_parts['user']) && isset($url_parts['pass']))
  6041. {
  6042. $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
  6043. }
  6044. foreach ($headers as $key => $value)
  6045. {
  6046. $out .= "$key: $value\r\n";
  6047. }
  6048. $out .= "Connection: Close\r\n\r\n";
  6049. fwrite($fp, $out);
  6050. $info = stream_get_meta_data($fp);
  6051. $this->headers = '';
  6052. while (!$info['eof'] && !$info['timed_out'])
  6053. {
  6054. $this->headers .= fread($fp, 1160);
  6055. $info = stream_get_meta_data($fp);
  6056. }
  6057. if (!$info['timed_out'])
  6058. {
  6059. $parser = new SimplePie_HTTP_Parser($this->headers);
  6060. if ($parser->parse())
  6061. {
  6062. $this->headers = $parser->headers;
  6063. $this->body = $parser->body;
  6064. $this->status_code = $parser->status_code;
  6065. 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)
  6066. {
  6067. $this->redirects++;
  6068. $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
  6069. return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
  6070. }
  6071. if (isset($this->headers['content-encoding']))
  6072. {
  6073. // Hey, we act dumb elsewhere, so let's do that here too
  6074. switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
  6075. {
  6076. case 'gzip':
  6077. case 'x-gzip':
  6078. $decoder = new SimplePie_gzdecode($this->body);
  6079. if (!$decoder->parse())
  6080. {
  6081. $this->error = 'Unable to decode HTTP "gzip" stream';
  6082. $this->success = false;
  6083. }
  6084. else
  6085. {
  6086. $this->body = $decoder->data;
  6087. }
  6088. break;
  6089. case 'deflate':
  6090. if (($decompressed = gzinflate($this->body)) !== false)
  6091. {
  6092. $this->body = $decompressed;
  6093. }
  6094. else if (($decompressed = gzuncompress($this->body)) !== false)
  6095. {
  6096. $this->body = $decompressed;
  6097. }
  6098. else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
  6099. {
  6100. $this->body = $decompressed;
  6101. }
  6102. else
  6103. {
  6104. $this->error = 'Unable to decode HTTP "deflate" stream';
  6105. $this->success = false;
  6106. }
  6107. break;
  6108. default:
  6109. $this->error = 'Unknown content coding';
  6110. $this->success = false;
  6111. }
  6112. }
  6113. }
  6114. }
  6115. else
  6116. {
  6117. $this->error = 'fsocket timed out';
  6118. $this->success = false;
  6119. }
  6120. fclose($fp);
  6121. }
  6122. }
  6123. }
  6124. else
  6125. {
  6126. $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
  6127. if (empty($url) || !($this->body = file_get_contents($url)))
  6128. {
  6129. $this->error = 'file_get_contents could not read the file';
  6130. $this->success = false;
  6131. }
  6132. }
  6133. }
  6134. }
  6135. /**
  6136. * IRI parser/serialiser/normaliser
  6137. *
  6138. * @package SimplePie
  6139. * @subpackage HTTP
  6140. * @author Geoffrey Sneddon
  6141. * @author Steve Minutillo
  6142. * @author Ryan McCue
  6143. * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
  6144. * @license http://www.opensource.org/licenses/bsd-license.php
  6145. */
  6146. class SimplePie_IRI
  6147. {
  6148. /**
  6149. * Scheme
  6150. *
  6151. * @var string
  6152. */
  6153. protected $scheme = null;
  6154. /**
  6155. * User Information
  6156. *
  6157. * @var string
  6158. */
  6159. protected $iuserinfo = null;
  6160. /**
  6161. * ihost
  6162. *
  6163. * @var string
  6164. */
  6165. protected $ihost = null;
  6166. /**
  6167. * Port
  6168. *
  6169. * @var string
  6170. */
  6171. protected $port = null;
  6172. /**
  6173. * ipath
  6174. *
  6175. * @var string
  6176. */
  6177. protected $ipath = '';
  6178. /**
  6179. * iquery
  6180. *
  6181. * @var string
  6182. */
  6183. protected $iquery = null;
  6184. /**
  6185. * ifragment
  6186. *
  6187. * @var string
  6188. */
  6189. protected $ifragment = null;
  6190. /**
  6191. * Normalization database
  6192. *
  6193. * Each key is the scheme, each value is an array with each key as the IRI
  6194. * part and value as the default value for that part.
  6195. */
  6196. protected $normalization = array(
  6197. 'acap' => array(
  6198. 'port' => 674
  6199. ),
  6200. 'dict' => array(
  6201. 'port' => 2628
  6202. ),
  6203. 'file' => array(
  6204. 'ihost' => 'localhost'
  6205. ),
  6206. 'http' => array(
  6207. 'port' => 80,
  6208. 'ipath' => '/'
  6209. ),
  6210. 'https' => array(
  6211. 'port' => 443,
  6212. 'ipath' => '/'
  6213. ),
  6214. );
  6215. /**
  6216. * Return the entire IRI when you try and read the object as a string
  6217. *
  6218. * @return string
  6219. */
  6220. public function __toString()
  6221. {
  6222. return $this->get_iri();
  6223. }
  6224. /**
  6225. * Overload __set() to provide access via properties
  6226. *
  6227. * @param string $name Property name
  6228. * @param mixed $value Property value
  6229. */
  6230. public function __set($name, $value)
  6231. {
  6232. if (method_exists($this, 'set_' . $name))
  6233. {
  6234. call_user_func(array($this, 'set_' . $name), $value);
  6235. }
  6236. elseif (
  6237. $name === 'iauthority'
  6238. || $name === 'iuserinfo'
  6239. || $name === 'ihost'
  6240. || $name === 'ipath'
  6241. || $name === 'iquery'
  6242. || $name === 'ifragment'
  6243. )
  6244. {
  6245. call_user_func(array($this, 'set_' . substr($name, 1)), $value);
  6246. }
  6247. }
  6248. /**
  6249. * Overload __get() to provide access via properties
  6250. *
  6251. * @param string $name Property name
  6252. * @return mixed
  6253. */
  6254. public function __get($name)
  6255. {
  6256. // isset() returns false for null, we don't want to do that
  6257. // Also why we use array_key_exists below instead of isset()
  6258. $props = get_object_vars($this);
  6259. if (
  6260. $name === 'iri' ||
  6261. $name === 'uri' ||
  6262. $name === 'iauthority' ||
  6263. $name === 'authority'
  6264. )
  6265. {
  6266. $return = $this->{"get_$name"}();
  6267. }
  6268. elseif (array_key_exists($name, $props))
  6269. {
  6270. $return = $this->$name;
  6271. }
  6272. // host -> ihost
  6273. elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
  6274. {
  6275. $name = $prop;
  6276. $return = $this->$prop;
  6277. }
  6278. // ischeme -> scheme
  6279. elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
  6280. {
  6281. $name = $prop;
  6282. $return = $this->$prop;
  6283. }
  6284. else
  6285. {
  6286. trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
  6287. $return = null;
  6288. }
  6289. if ($return === null && isset($this->normalization[$this->scheme][$name]))
  6290. {
  6291. return $this->normalization[$this->scheme][$name];
  6292. }
  6293. else
  6294. {
  6295. return $return;
  6296. }
  6297. }
  6298. /**
  6299. * Overload __isset() to provide access via properties
  6300. *
  6301. * @param string $name Property name
  6302. * @return bool
  6303. */
  6304. public function __isset($name)
  6305. {
  6306. if (method_exists($this, 'get_' . $name) || isset($this->$name))
  6307. {
  6308. return true;
  6309. }
  6310. else
  6311. {
  6312. return false;
  6313. }
  6314. }
  6315. /**
  6316. * Overload __unset() to provide access via properties
  6317. *
  6318. * @param string $name Property name
  6319. */
  6320. public function __unset($name)
  6321. {
  6322. if (method_exists($this, 'set_' . $name))
  6323. {
  6324. call_user_func(array($this, 'set_' . $name), '');
  6325. }
  6326. }
  6327. /**
  6328. * Create a new IRI object, from a specified string
  6329. *
  6330. * @param string $iri
  6331. */
  6332. public function __construct($iri = null)
  6333. {
  6334. $this->set_iri($iri);
  6335. }
  6336. /**
  6337. * Create a new IRI object by resolving a relative IRI
  6338. *
  6339. * Returns false if $base is not absolute, otherwise an IRI.
  6340. *
  6341. * @param IRI|string $base (Absolute) Base IRI
  6342. * @param IRI|string $relative Relative IRI
  6343. * @return IRI|false
  6344. */
  6345. public static function absolutize($base, $relative)
  6346. {
  6347. if (!($relative instanceof SimplePie_IRI))
  6348. {
  6349. $relative = new SimplePie_IRI($relative);
  6350. }
  6351. if (!$relative->is_valid())
  6352. {
  6353. return false;
  6354. }
  6355. elseif ($relative->scheme !== null)
  6356. {
  6357. return clone $relative;
  6358. }
  6359. else
  6360. {
  6361. if (!($base instanceof SimplePie_IRI))
  6362. {
  6363. $base = new SimplePie_IRI($base);
  6364. }
  6365. if ($base->scheme !== null && $base->is_valid())
  6366. {
  6367. if ($relative->get_iri() !== '')
  6368. {
  6369. if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
  6370. {
  6371. $target = clone $relative;
  6372. $target->scheme = $base->scheme;
  6373. }
  6374. else
  6375. {
  6376. $target = new SimplePie_IRI;
  6377. $target->scheme = $base->scheme;
  6378. $target->iuserinfo = $base->iuserinfo;
  6379. $target->ihost = $base->ihost;
  6380. $target->port = $base->port;
  6381. if ($relative->ipath !== '')
  6382. {
  6383. if ($relative->ipath[0] === '/')
  6384. {
  6385. $target->ipath = $relative->ipath;
  6386. }
  6387. elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
  6388. {
  6389. $target->ipath = '/' . $relative->ipath;
  6390. }
  6391. elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
  6392. {
  6393. $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
  6394. }
  6395. else
  6396. {
  6397. $target->ipath = $relative->ipath;
  6398. }
  6399. $target->ipath = $target->remove_dot_segments($target->ipath);
  6400. $target->iquery = $relative->iquery;
  6401. }
  6402. else
  6403. {
  6404. $target->ipath = $base->ipath;
  6405. if ($relative->iquery !== null)
  6406. {
  6407. $target->iquery = $relative->iquery;
  6408. }
  6409. elseif ($base->iquery !== null)
  6410. {
  6411. $target->iquery = $base->iquery;
  6412. }
  6413. }
  6414. $target->ifragment = $relative->ifragment;
  6415. }
  6416. }
  6417. else
  6418. {
  6419. $target = clone $base;
  6420. $target->ifragment = null;
  6421. }
  6422. $target->scheme_normalization();
  6423. return $target;
  6424. }
  6425. else
  6426. {
  6427. return false;
  6428. }
  6429. }
  6430. }
  6431. /**
  6432. * Parse an IRI into scheme/authority/path/query/fragment segments
  6433. *
  6434. * @param string $iri
  6435. * @return array
  6436. */
  6437. protected function parse_iri($iri)
  6438. {
  6439. $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
  6440. if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
  6441. {
  6442. if ($match[1] === '')
  6443. {
  6444. $match['scheme'] = null;
  6445. }
  6446. if (!isset($match[3]) || $match[3] === '')
  6447. {
  6448. $match['authority'] = null;
  6449. }
  6450. if (!isset($match[5]))
  6451. {
  6452. $match['path'] = '';
  6453. }
  6454. if (!isset($match[6]) || $match[6] === '')
  6455. {
  6456. $match['query'] = null;
  6457. }
  6458. if (!isset($match[8]) || $match[8] === '')
  6459. {
  6460. $match['fragment'] = null;
  6461. }
  6462. return $match;
  6463. }
  6464. else
  6465. {
  6466. // This can occur when a paragraph is accidentally parsed as a URI
  6467. return false;
  6468. }
  6469. }
  6470. /**
  6471. * Remove dot segments from a path
  6472. *
  6473. * @param string $input
  6474. * @return string
  6475. */
  6476. protected function remove_dot_segments($input)
  6477. {
  6478. $output = '';
  6479. while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
  6480. {
  6481. // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
  6482. if (strpos($input, '../') === 0)
  6483. {
  6484. $input = substr($input, 3);
  6485. }
  6486. elseif (strpos($input, './') === 0)
  6487. {
  6488. $input = substr($input, 2);
  6489. }
  6490. // 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,
  6491. elseif (strpos($input, '/./') === 0)
  6492. {
  6493. $input = substr($input, 2);
  6494. }
  6495. elseif ($input === '/.')
  6496. {
  6497. $input = '/';
  6498. }
  6499. // 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,
  6500. elseif (strpos($input, '/../') === 0)
  6501. {
  6502. $input = substr($input, 3);
  6503. $output = substr_replace($output, '', strrpos($output, '/'));
  6504. }
  6505. elseif ($input === '/..')
  6506. {
  6507. $input = '/';
  6508. $output = substr_replace($output, '', strrpos($output, '/'));
  6509. }
  6510. // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
  6511. elseif ($input === '.' || $input === '..')
  6512. {
  6513. $input = '';
  6514. }
  6515. // 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
  6516. elseif (($pos = strpos($input, '/', 1)) !== false)
  6517. {
  6518. $output .= substr($input, 0, $pos);
  6519. $input = substr_replace($input, '', 0, $pos);
  6520. }
  6521. else
  6522. {
  6523. $output .= $input;
  6524. $input = '';
  6525. }
  6526. }
  6527. return $output . $input;
  6528. }
  6529. /**
  6530. * Replace invalid character with percent encoding
  6531. *
  6532. * @param string $string Input string
  6533. * @param string $extra_chars Valid characters not in iunreserved or
  6534. * iprivate (this is ASCII-only)
  6535. * @param bool $iprivate Allow iprivate
  6536. * @return string
  6537. */
  6538. protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
  6539. {
  6540. // Normalize as many pct-encoded sections as possible
  6541. $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
  6542. // Replace invalid percent characters
  6543. $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
  6544. // Add unreserved and % to $extra_chars (the latter is safe because all
  6545. // pct-encoded sections are now valid).
  6546. $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
  6547. // Now replace any bytes that aren't allowed with their pct-encoded versions
  6548. $position = 0;
  6549. $strlen = strlen($string);
  6550. while (($position += strspn($string, $extra_chars, $position)) < $strlen)
  6551. {
  6552. $value = ord($string[$position]);
  6553. // Start position
  6554. $start = $position;
  6555. // By default we are valid
  6556. $valid = true;
  6557. // No one byte sequences are valid due to the while.
  6558. // Two byte sequence:
  6559. if (($value & 0xE0) === 0xC0)
  6560. {
  6561. $character = ($value & 0x1F) << 6;
  6562. $length = 2;
  6563. $remaining = 1;
  6564. }
  6565. // Three byte sequence:
  6566. elseif (($value & 0xF0) === 0xE0)
  6567. {
  6568. $character = ($value & 0x0F) << 12;
  6569. $length = 3;
  6570. $remaining = 2;
  6571. }
  6572. // Four byte sequence:
  6573. elseif (($value & 0xF8) === 0xF0)
  6574. {
  6575. $character = ($value & 0x07) << 18;
  6576. $length = 4;
  6577. $remaining = 3;
  6578. }
  6579. // Invalid byte:
  6580. else
  6581. {
  6582. $valid = false;
  6583. $length = 1;
  6584. $remaining = 0;
  6585. }
  6586. if ($remaining)
  6587. {
  6588. if ($position + $length <= $strlen)
  6589. {
  6590. for ($position++; $remaining; $position++)
  6591. {
  6592. $value = ord($string[$position]);
  6593. // Check that the byte is valid, then add it to the character:
  6594. if (($value & 0xC0) === 0x80)
  6595. {
  6596. $character |= ($value & 0x3F) << (--$remaining * 6);
  6597. }
  6598. // If it is invalid, count the sequence as invalid and reprocess the current byte:
  6599. else
  6600. {
  6601. $valid = false;
  6602. $position--;
  6603. break;
  6604. }
  6605. }
  6606. }
  6607. else
  6608. {
  6609. $position = $strlen - 1;
  6610. $valid = false;
  6611. }
  6612. }
  6613. // Percent encode anything invalid or not in ucschar
  6614. if (
  6615. // Invalid sequences
  6616. !$valid
  6617. // Non-shortest form sequences are invalid
  6618. || $length > 1 && $character <= 0x7F
  6619. || $length > 2 && $character <= 0x7FF
  6620. || $length > 3 && $character <= 0xFFFF
  6621. // Outside of range of ucschar codepoints
  6622. // Noncharacters
  6623. || ($character & 0xFFFE) === 0xFFFE
  6624. || $character >= 0xFDD0 && $character <= 0xFDEF
  6625. || (
  6626. // Everything else not in ucschar
  6627. $character > 0xD7FF && $character < 0xF900
  6628. || $character < 0xA0
  6629. || $character > 0xEFFFD
  6630. )
  6631. && (
  6632. // Everything not in iprivate, if it applies
  6633. !$iprivate
  6634. || $character < 0xE000
  6635. || $character > 0x10FFFD
  6636. )
  6637. )
  6638. {
  6639. // If we were a character, pretend we weren't, but rather an error.
  6640. if ($valid)
  6641. $position--;
  6642. for ($j = $start; $j <= $position; $j++)
  6643. {
  6644. $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
  6645. $j += 2;
  6646. $position += 2;
  6647. $strlen += 2;
  6648. }
  6649. }
  6650. }
  6651. return $string;
  6652. }
  6653. /**
  6654. * Callback function for preg_replace_callback.
  6655. *
  6656. * Removes sequences of percent encoded bytes that represent UTF-8
  6657. * encoded characters in iunreserved
  6658. *
  6659. * @param array $match PCRE match
  6660. * @return string Replacement
  6661. */
  6662. protected function remove_iunreserved_percent_encoded($match)
  6663. {
  6664. // As we just have valid percent encoded sequences we can just explode
  6665. // and ignore the first member of the returned array (an empty string).
  6666. $bytes = explode('%', $match[0]);
  6667. // Initialize the new string (this is what will be returned) and that
  6668. // there are no bytes remaining in the current sequence (unsurprising
  6669. // at the first byte!).
  6670. $string = '';
  6671. $remaining = 0;
  6672. // Loop over each and every byte, and set $value to its value
  6673. for ($i = 1, $len = count($bytes); $i < $len; $i++)
  6674. {
  6675. $value = hexdec($bytes[$i]);
  6676. // If we're the first byte of sequence:
  6677. if (!$remaining)
  6678. {
  6679. // Start position
  6680. $start = $i;
  6681. // By default we are valid
  6682. $valid = true;
  6683. // One byte sequence:
  6684. if ($value <= 0x7F)
  6685. {
  6686. $character = $value;
  6687. $length = 1;
  6688. }
  6689. // Two byte sequence:
  6690. elseif (($value & 0xE0) === 0xC0)
  6691. {
  6692. $character = ($value & 0x1F) << 6;
  6693. $length = 2;
  6694. $remaining = 1;
  6695. }
  6696. // Three byte sequence:
  6697. elseif (($value & 0xF0) === 0xE0)
  6698. {
  6699. $character = ($value & 0x0F) << 12;
  6700. $length = 3;
  6701. $remaining = 2;
  6702. }
  6703. // Four byte sequence:
  6704. elseif (($value & 0xF8) === 0xF0)
  6705. {
  6706. $character = ($value & 0x07) << 18;
  6707. $length = 4;
  6708. $remaining = 3;
  6709. }
  6710. // Invalid byte:
  6711. else
  6712. {
  6713. $valid = false;
  6714. $remaining = 0;
  6715. }
  6716. }
  6717. // Continuation byte:
  6718. else
  6719. {
  6720. // Check that the byte is valid, then add it to the character:
  6721. if (($value & 0xC0) === 0x80)
  6722. {
  6723. $remaining--;
  6724. $character |= ($value & 0x3F) << ($remaining * 6);
  6725. }
  6726. // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
  6727. else
  6728. {
  6729. $valid = false;
  6730. $remaining = 0;
  6731. $i--;
  6732. }
  6733. }
  6734. // If we've reached the end of the current byte sequence, append it to Unicode::$data
  6735. if (!$remaining)
  6736. {
  6737. // Percent encode anything invalid or not in iunreserved
  6738. if (
  6739. // Invalid sequences
  6740. !$valid
  6741. // Non-shortest form sequences are invalid
  6742. || $length > 1 && $character <= 0x7F
  6743. || $length > 2 && $character <= 0x7FF
  6744. || $length > 3 && $character <= 0xFFFF
  6745. // Outside of range of iunreserved codepoints
  6746. || $character < 0x2D
  6747. || $character > 0xEFFFD
  6748. // Noncharacters
  6749. || ($character & 0xFFFE) === 0xFFFE
  6750. || $character >= 0xFDD0 && $character <= 0xFDEF
  6751. // Everything else not in iunreserved (this is all BMP)
  6752. || $character === 0x2F
  6753. || $character > 0x39 && $character < 0x41
  6754. || $character > 0x5A && $character < 0x61
  6755. || $character > 0x7A && $character < 0x7E
  6756. || $character > 0x7E && $character < 0xA0
  6757. || $character > 0xD7FF && $character < 0xF900
  6758. )
  6759. {
  6760. for ($j = $start; $j <= $i; $j++)
  6761. {
  6762. $string .= '%' . strtoupper($bytes[$j]);
  6763. }
  6764. }
  6765. else
  6766. {
  6767. for ($j = $start; $j <= $i; $j++)
  6768. {
  6769. $string .= chr(hexdec($bytes[$j]));
  6770. }
  6771. }
  6772. }
  6773. }
  6774. // If we have any bytes left over they are invalid (i.e., we are
  6775. // mid-way through a multi-byte sequence)
  6776. if ($remaining)
  6777. {
  6778. for ($j = $start; $j < $len; $j++)
  6779. {
  6780. $string .= '%' . strtoupper($bytes[$j]);
  6781. }
  6782. }
  6783. return $string;
  6784. }
  6785. protected function scheme_normalization()
  6786. {
  6787. if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
  6788. {
  6789. $this->iuserinfo = null;
  6790. }
  6791. if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
  6792. {
  6793. $this->ihost = null;
  6794. }
  6795. if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
  6796. {
  6797. $this->port = null;
  6798. }
  6799. if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
  6800. {
  6801. $this->ipath = '';
  6802. }
  6803. if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
  6804. {
  6805. $this->iquery = null;
  6806. }
  6807. if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
  6808. {
  6809. $this->ifragment = null;
  6810. }
  6811. }
  6812. /**
  6813. * Check if the object represents a valid IRI. This needs to be done on each
  6814. * call as some things change depending on another part of the IRI.
  6815. *
  6816. * @return bool
  6817. */
  6818. public function is_valid()
  6819. {
  6820. $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
  6821. if ($this->ipath !== '' &&
  6822. (
  6823. $isauthority && (
  6824. $this->ipath[0] !== '/' ||
  6825. substr($this->ipath, 0, 2) === '//'
  6826. ) ||
  6827. (
  6828. $this->scheme === null &&
  6829. !$isauthority &&
  6830. strpos($this->ipath, ':') !== false &&
  6831. (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
  6832. )
  6833. )
  6834. )
  6835. {
  6836. return false;
  6837. }
  6838. return true;
  6839. }
  6840. /**
  6841. * Set the entire IRI. Returns true on success, false on failure (if there
  6842. * are any invalid characters).
  6843. *
  6844. * @param string $iri
  6845. * @return bool
  6846. */
  6847. public function set_iri($iri)
  6848. {
  6849. static $cache;
  6850. if (!$cache)
  6851. {
  6852. $cache = array();
  6853. }
  6854. if ($iri === null)
  6855. {
  6856. return true;
  6857. }
  6858. elseif (isset($cache[$iri]))
  6859. {
  6860. list($this->scheme,
  6861. $this->iuserinfo,
  6862. $this->ihost,
  6863. $this->port,
  6864. $this->ipath,
  6865. $this->iquery,
  6866. $this->ifragment,
  6867. $return) = $cache[$iri];
  6868. return $return;
  6869. }
  6870. else
  6871. {
  6872. $parsed = $this->parse_iri((string) $iri);
  6873. if (!$parsed)
  6874. {
  6875. return false;
  6876. }
  6877. $return = $this->set_scheme($parsed['scheme'])
  6878. && $this->set_authority($parsed['authority'])
  6879. && $this->set_path($parsed['path'])
  6880. && $this->set_query($parsed['query'])
  6881. && $this->set_fragment($parsed['fragment']);
  6882. $cache[$iri] = array($this->scheme,
  6883. $this->iuserinfo,
  6884. $this->ihost,
  6885. $this->port,
  6886. $this->ipath,
  6887. $this->iquery,
  6888. $this->ifragment,
  6889. $return);
  6890. return $return;
  6891. }
  6892. }
  6893. /**
  6894. * Set the scheme. Returns true on success, false on failure (if there are
  6895. * any invalid characters).
  6896. *
  6897. * @param string $scheme
  6898. * @return bool
  6899. */
  6900. public function set_scheme($scheme)
  6901. {
  6902. if ($scheme === null)
  6903. {
  6904. $this->scheme = null;
  6905. }
  6906. elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
  6907. {
  6908. $this->scheme = null;
  6909. return false;
  6910. }
  6911. else
  6912. {
  6913. $this->scheme = strtolower($scheme);
  6914. }
  6915. return true;
  6916. }
  6917. /**
  6918. * Set the authority. Returns true on success, false on failure (if there are
  6919. * any invalid characters).
  6920. *
  6921. * @param string $authority
  6922. * @return bool
  6923. */
  6924. public function set_authority($authority)
  6925. {
  6926. static $cache;
  6927. if (!$cache)
  6928. $cache = array();
  6929. if ($authority === null)
  6930. {
  6931. $this->iuserinfo = null;
  6932. $this->ihost = null;
  6933. $this->port = null;
  6934. return true;
  6935. }
  6936. elseif (isset($cache[$authority]))
  6937. {
  6938. list($this->iuserinfo,
  6939. $this->ihost,
  6940. $this->port,
  6941. $return) = $cache[$authority];
  6942. return $return;
  6943. }
  6944. else
  6945. {
  6946. $remaining = $authority;
  6947. if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
  6948. {
  6949. $iuserinfo = substr($remaining, 0, $iuserinfo_end);
  6950. $remaining = substr($remaining, $iuserinfo_end + 1);
  6951. }
  6952. else
  6953. {
  6954. $iuserinfo = null;
  6955. }
  6956. if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
  6957. {
  6958. if (($port = substr($remaining, $port_start + 1)) === false)
  6959. {
  6960. $port = null;
  6961. }
  6962. $remaining = substr($remaining, 0, $port_start);
  6963. }
  6964. else
  6965. {
  6966. $port = null;
  6967. }
  6968. $return = $this->set_userinfo($iuserinfo) &&
  6969. $this->set_host($remaining) &&
  6970. $this->set_port($port);
  6971. $cache[$authority] = array($this->iuserinfo,
  6972. $this->ihost,
  6973. $this->port,
  6974. $return);
  6975. return $return;
  6976. }
  6977. }
  6978. /**
  6979. * Set the iuserinfo.
  6980. *
  6981. * @param string $iuserinfo
  6982. * @return bool
  6983. */
  6984. public function set_userinfo($iuserinfo)
  6985. {
  6986. if ($iuserinfo === null)
  6987. {
  6988. $this->iuserinfo = null;
  6989. }
  6990. else
  6991. {
  6992. $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
  6993. $this->scheme_normalization();
  6994. }
  6995. return true;
  6996. }
  6997. /**
  6998. * Set the ihost. Returns true on success, false on failure (if there are
  6999. * any invalid characters).
  7000. *
  7001. * @param string $ihost
  7002. * @return bool
  7003. */
  7004. public function set_host($ihost)
  7005. {
  7006. if ($ihost === null)
  7007. {
  7008. $this->ihost = null;
  7009. return true;
  7010. }
  7011. elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
  7012. {
  7013. if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
  7014. {
  7015. $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
  7016. }
  7017. else
  7018. {
  7019. $this->ihost = null;
  7020. return false;
  7021. }
  7022. }
  7023. else
  7024. {
  7025. $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
  7026. // Lowercase, but ignore pct-encoded sections (as they should
  7027. // remain uppercase). This must be done after the previous step
  7028. // as that can add unescaped characters.
  7029. $position = 0;
  7030. $strlen = strlen($ihost);
  7031. while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
  7032. {
  7033. if ($ihost[$position] === '%')
  7034. {
  7035. $position += 3;
  7036. }
  7037. else
  7038. {
  7039. $ihost[$position] = strtolower($ihost[$position]);
  7040. $position++;
  7041. }
  7042. }
  7043. $this->ihost = $ihost;
  7044. }
  7045. $this->scheme_normalization();
  7046. return true;
  7047. }
  7048. /**
  7049. * Set the port. Returns true on success, false on failure (if there are
  7050. * any invalid characters).
  7051. *
  7052. * @param string $port
  7053. * @return bool
  7054. */
  7055. public function set_port($port)
  7056. {
  7057. if ($port === null)
  7058. {
  7059. $this->port = null;
  7060. return true;
  7061. }
  7062. elseif (strspn($port, '0123456789') === strlen($port))
  7063. {
  7064. $this->port = (int) $port;
  7065. $this->scheme_normalization();
  7066. return true;
  7067. }
  7068. else
  7069. {
  7070. $this->port = null;
  7071. return false;
  7072. }
  7073. }
  7074. /**
  7075. * Set the ipath.
  7076. *
  7077. * @param string $ipath
  7078. * @return bool
  7079. */
  7080. public function set_path($ipath)
  7081. {
  7082. static $cache;
  7083. if (!$cache)
  7084. {
  7085. $cache = array();
  7086. }
  7087. $ipath = (string) $ipath;
  7088. if (isset($cache[$ipath]))
  7089. {
  7090. $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
  7091. }
  7092. else
  7093. {
  7094. $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
  7095. $removed = $this->remove_dot_segments($valid);
  7096. $cache[$ipath] = array($valid, $removed);
  7097. $this->ipath = ($this->scheme !== null) ? $removed : $valid;
  7098. }
  7099. $this->scheme_normalization();
  7100. return true;
  7101. }
  7102. /**
  7103. * Set the iquery.
  7104. *
  7105. * @param string $iquery
  7106. * @return bool
  7107. */
  7108. public function set_query($iquery)
  7109. {
  7110. if ($iquery === null)
  7111. {
  7112. $this->iquery = null;
  7113. }
  7114. else
  7115. {
  7116. $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
  7117. $this->scheme_normalization();
  7118. }
  7119. return true;
  7120. }
  7121. /**
  7122. * Set the ifragment.
  7123. *
  7124. * @param string $ifragment
  7125. * @return bool
  7126. */
  7127. public function set_fragment($ifragment)
  7128. {
  7129. if ($ifragment === null)
  7130. {
  7131. $this->ifragment = null;
  7132. }
  7133. else
  7134. {
  7135. $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
  7136. $this->scheme_normalization();
  7137. }
  7138. return true;
  7139. }
  7140. /**
  7141. * Convert an IRI to a URI (or parts thereof)
  7142. *
  7143. * @return string
  7144. */
  7145. public function to_uri($string)
  7146. {
  7147. static $non_ascii;
  7148. if (!$non_ascii)
  7149. {
  7150. $non_ascii = implode('', range("\x80", "\xFF"));
  7151. }
  7152. $position = 0;
  7153. $strlen = strlen($string);
  7154. while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
  7155. {
  7156. $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
  7157. $position += 3;
  7158. $strlen += 2;
  7159. }
  7160. return $string;
  7161. }
  7162. /**
  7163. * Get the complete IRI
  7164. *
  7165. * @return string
  7166. */
  7167. public function get_iri()
  7168. {
  7169. if (!$this->is_valid())
  7170. {
  7171. return false;
  7172. }
  7173. $iri = '';
  7174. if ($this->scheme !== null)
  7175. {
  7176. $iri .= $this->scheme . ':';
  7177. }
  7178. if (($iauthority = $this->get_iauthority()) !== null)
  7179. {
  7180. $iri .= '//' . $iauthority;
  7181. }
  7182. if ($this->ipath !== '')
  7183. {
  7184. $iri .= $this->ipath;
  7185. }
  7186. elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
  7187. {
  7188. $iri .= $this->normalization[$this->scheme]['ipath'];
  7189. }
  7190. if ($this->iquery !== null)
  7191. {
  7192. $iri .= '?' . $this->iquery;
  7193. }
  7194. if ($this->ifragment !== null)
  7195. {
  7196. $iri .= '#' . $this->ifragment;
  7197. }
  7198. return $iri;
  7199. }
  7200. /**
  7201. * Get the complete URI
  7202. *
  7203. * @return string
  7204. */
  7205. public function get_uri()
  7206. {
  7207. return $this->to_uri($this->get_iri());
  7208. }
  7209. /**
  7210. * Get the complete iauthority
  7211. *
  7212. * @return string
  7213. */
  7214. protected function get_iauthority()
  7215. {
  7216. if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
  7217. {
  7218. $iauthority = '';
  7219. if ($this->iuserinfo !== null)
  7220. {
  7221. $iauthority .= $this->iuserinfo . '@';
  7222. }
  7223. if ($this->ihost !== null)
  7224. {
  7225. $iauthority .= $this->ihost;
  7226. }
  7227. if ($this->port !== null)
  7228. {
  7229. $iauthority .= ':' . $this->port;
  7230. }
  7231. return $iauthority;
  7232. }
  7233. else
  7234. {
  7235. return null;
  7236. }
  7237. }
  7238. /**
  7239. * Get the complete authority
  7240. *
  7241. * @return string
  7242. */
  7243. protected function get_authority()
  7244. {
  7245. $iauthority = $this->get_iauthority();
  7246. if (is_string($iauthority))
  7247. return $this->to_uri($iauthority);
  7248. else
  7249. return $iauthority;
  7250. }
  7251. }
  7252. /**
  7253. * Handles `<media:credit>` as defined in Media RSS
  7254. *
  7255. * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
  7256. *
  7257. * This class can be overloaded with {@see SimplePie::set_credit_class()}
  7258. *
  7259. * @package SimplePie
  7260. * @subpackage API
  7261. */
  7262. class SimplePie_Credit
  7263. {
  7264. /**
  7265. * Credited role
  7266. *
  7267. * @var string
  7268. * @see get_role()
  7269. */
  7270. var $role;
  7271. /**
  7272. * Organizational scheme
  7273. *
  7274. * @var string
  7275. * @see get_scheme()
  7276. */
  7277. var $scheme;
  7278. /**
  7279. * Credited name
  7280. *
  7281. * @var string
  7282. * @see get_name()
  7283. */
  7284. var $name;
  7285. /**
  7286. * Constructor, used to input the data
  7287. *
  7288. * For documentation on all the parameters, see the corresponding
  7289. * properties and their accessors
  7290. */
  7291. public function __construct($role = null, $scheme = null, $name = null)
  7292. {
  7293. $this->role = $role;
  7294. $this->scheme = $scheme;
  7295. $this->name = $name;
  7296. }
  7297. /**
  7298. * String-ified version
  7299. *
  7300. * @return string
  7301. */
  7302. public function __toString()
  7303. {
  7304. // There is no $this->data here
  7305. return md5(serialize($this));
  7306. }
  7307. /**
  7308. * Get the role of the person receiving credit
  7309. *
  7310. * @return string|null
  7311. */
  7312. public function get_role()
  7313. {
  7314. if ($this->role !== null)
  7315. {
  7316. return $this->role;
  7317. }
  7318. else
  7319. {
  7320. return null;
  7321. }
  7322. }
  7323. /**
  7324. * Get the organizational scheme
  7325. *
  7326. * @return string|null
  7327. */
  7328. public function get_scheme()
  7329. {
  7330. if ($this->scheme !== null)
  7331. {
  7332. return $this->scheme;
  7333. }
  7334. else
  7335. {
  7336. return null;
  7337. }
  7338. }
  7339. /**
  7340. * Get the credited person/entity's name
  7341. *
  7342. * @return string|null
  7343. */
  7344. public function get_name()
  7345. {
  7346. if ($this->name !== null)
  7347. {
  7348. return $this->name;
  7349. }
  7350. else
  7351. {
  7352. return null;
  7353. }
  7354. }
  7355. }
  7356. /**
  7357. * Class to validate and to work with IPv6 addresses.
  7358. *
  7359. * @package SimplePie
  7360. * @subpackage HTTP
  7361. * @copyright 2003-2005 The PHP Group
  7362. * @license http://www.opensource.org/licenses/bsd-license.php
  7363. * @link http://pear.php.net/package/Net_IPv6
  7364. * @author Alexander Merz <alexander.merz@web.de>
  7365. * @author elfrink at introweb dot nl
  7366. * @author Josh Peck <jmp at joshpeck dot org>
  7367. * @author Geoffrey Sneddon <geoffers@gmail.com>
  7368. */
  7369. class SimplePie_Net_IPv6
  7370. {
  7371. /**
  7372. * Uncompresses an IPv6 address
  7373. *
  7374. * RFC 4291 allows you to compress concecutive zero pieces in an address to
  7375. * '::'. This method expects a valid IPv6 address and expands the '::' to
  7376. * the required number of zero pieces.
  7377. *
  7378. * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
  7379. * ::1 -> 0:0:0:0:0:0:0:1
  7380. *
  7381. * @author Alexander Merz <alexander.merz@web.de>
  7382. * @author elfrink at introweb dot nl
  7383. * @author Josh Peck <jmp at joshpeck dot org>
  7384. * @copyright 2003-2005 The PHP Group
  7385. * @license http://www.opensource.org/licenses/bsd-license.php
  7386. * @param string $ip An IPv6 address
  7387. * @return string The uncompressed IPv6 address
  7388. */
  7389. public static function uncompress($ip)
  7390. {
  7391. $c1 = -1;
  7392. $c2 = -1;
  7393. if (substr_count($ip, '::') === 1)
  7394. {
  7395. list($ip1, $ip2) = explode('::', $ip);
  7396. if ($ip1 === '')
  7397. {
  7398. $c1 = -1;
  7399. }
  7400. else
  7401. {
  7402. $c1 = substr_count($ip1, ':');
  7403. }
  7404. if ($ip2 === '')
  7405. {
  7406. $c2 = -1;
  7407. }
  7408. else
  7409. {
  7410. $c2 = substr_count($ip2, ':');
  7411. }
  7412. if (strpos($ip2, '.') !== false)
  7413. {
  7414. $c2++;
  7415. }
  7416. // ::
  7417. if ($c1 === -1 && $c2 === -1)
  7418. {
  7419. $ip = '0:0:0:0:0:0:0:0';
  7420. }
  7421. // ::xxx
  7422. else if ($c1 === -1)
  7423. {
  7424. $fill = str_repeat('0:', 7 - $c2);
  7425. $ip = str_replace('::', $fill, $ip);
  7426. }
  7427. // xxx::
  7428. else if ($c2 === -1)
  7429. {
  7430. $fill = str_repeat(':0', 7 - $c1);
  7431. $ip = str_replace('::', $fill, $ip);
  7432. }
  7433. // xxx::xxx
  7434. else
  7435. {
  7436. $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
  7437. $ip = str_replace('::', $fill, $ip);
  7438. }
  7439. }
  7440. return $ip;
  7441. }
  7442. /**
  7443. * Compresses an IPv6 address
  7444. *
  7445. * RFC 4291 allows you to compress concecutive zero pieces in an address to
  7446. * '::'. This method expects a valid IPv6 address and compresses consecutive
  7447. * zero pieces to '::'.
  7448. *
  7449. * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
  7450. * 0:0:0:0:0:0:0:1 -> ::1
  7451. *
  7452. * @see uncompress()
  7453. * @param string $ip An IPv6 address
  7454. * @return string The compressed IPv6 address
  7455. */
  7456. public static function compress($ip)
  7457. {
  7458. // Prepare the IP to be compressed
  7459. $ip = self::uncompress($ip);
  7460. $ip_parts = self::split_v6_v4($ip);
  7461. // Replace all leading zeros
  7462. $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
  7463. // Find bunches of zeros
  7464. if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
  7465. {
  7466. $max = 0;
  7467. $pos = null;
  7468. foreach ($matches[0] as $match)
  7469. {
  7470. if (strlen($match[0]) > $max)
  7471. {
  7472. $max = strlen($match[0]);
  7473. $pos = $match[1];
  7474. }
  7475. }
  7476. $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
  7477. }
  7478. if ($ip_parts[1] !== '')
  7479. {
  7480. return implode(':', $ip_parts);
  7481. }
  7482. else
  7483. {
  7484. return $ip_parts[0];
  7485. }
  7486. }
  7487. /**
  7488. * Splits an IPv6 address into the IPv6 and IPv4 representation parts
  7489. *
  7490. * RFC 4291 allows you to represent the last two parts of an IPv6 address
  7491. * using the standard IPv4 representation
  7492. *
  7493. * Example: 0:0:0:0:0:0:13.1.68.3
  7494. * 0:0:0:0:0:FFFF:129.144.52.38
  7495. *
  7496. * @param string $ip An IPv6 address
  7497. * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
  7498. */
  7499. private static function split_v6_v4($ip)
  7500. {
  7501. if (strpos($ip, '.') !== false)
  7502. {
  7503. $pos = strrpos($ip, ':');
  7504. $ipv6_part = substr($ip, 0, $pos);
  7505. $ipv4_part = substr($ip, $pos + 1);
  7506. return array($ipv6_part, $ipv4_part);
  7507. }
  7508. else
  7509. {
  7510. return array($ip, '');
  7511. }
  7512. }
  7513. /**
  7514. * Checks an IPv6 address
  7515. *
  7516. * Checks if the given IP is a valid IPv6 address
  7517. *
  7518. * @param string $ip An IPv6 address
  7519. * @return bool true if $ip is a valid IPv6 address
  7520. */
  7521. public static function check_ipv6($ip)
  7522. {
  7523. $ip = self::uncompress($ip);
  7524. list($ipv6, $ipv4) = self::split_v6_v4($ip);
  7525. $ipv6 = explode(':', $ipv6);
  7526. $ipv4 = explode('.', $ipv4);
  7527. if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
  7528. {
  7529. foreach ($ipv6 as $ipv6_part)
  7530. {
  7531. // The section can't be empty
  7532. if ($ipv6_part === '')
  7533. return false;
  7534. // Nor can it be over four characters
  7535. if (strlen($ipv6_part) > 4)
  7536. return false;
  7537. // Remove leading zeros (this is safe because of the above)
  7538. $ipv6_part = ltrim($ipv6_part, '0');
  7539. if ($ipv6_part === '')
  7540. $ipv6_part = '0';
  7541. // Check the value is valid
  7542. $value = hexdec($ipv6_part);
  7543. if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
  7544. return false;
  7545. }
  7546. if (count($ipv4) === 4)
  7547. {
  7548. foreach ($ipv4 as $ipv4_part)
  7549. {
  7550. $value = (int) $ipv4_part;
  7551. if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
  7552. return false;
  7553. }
  7554. }
  7555. return true;
  7556. }
  7557. else
  7558. {
  7559. return false;
  7560. }
  7561. }
  7562. /**
  7563. * Checks if the given IP is a valid IPv6 address
  7564. *
  7565. * @codeCoverageIgnore
  7566. * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
  7567. * @see check_ipv6
  7568. * @param string $ip An IPv6 address
  7569. * @return bool true if $ip is a valid IPv6 address
  7570. */
  7571. public static function checkIPv6($ip)
  7572. {
  7573. return self::check_ipv6($ip);
  7574. }
  7575. }
  7576. /**
  7577. * Manages all category-related data
  7578. *
  7579. * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
  7580. *
  7581. * This class can be overloaded with {@see SimplePie::set_category_class()}
  7582. *
  7583. * @package SimplePie
  7584. * @subpackage API
  7585. */
  7586. class SimplePie_Category
  7587. {
  7588. /**
  7589. * Category identifier
  7590. *
  7591. * @var string
  7592. * @see get_term
  7593. */
  7594. var $term;
  7595. /**
  7596. * Categorization scheme identifier
  7597. *
  7598. * @var string
  7599. * @see get_scheme()
  7600. */
  7601. var $scheme;
  7602. /**
  7603. * Human readable label
  7604. *
  7605. * @var string
  7606. * @see get_label()
  7607. */
  7608. var $label;
  7609. /**
  7610. * Constructor, used to input the data
  7611. *
  7612. * @param string $term
  7613. * @param string $scheme
  7614. * @param string $label
  7615. */
  7616. public function __construct($term = null, $scheme = null, $label = null)
  7617. {
  7618. $this->term = $term;
  7619. $this->scheme = $scheme;
  7620. $this->label = $label;
  7621. }
  7622. /**
  7623. * String-ified version
  7624. *
  7625. * @return string
  7626. */
  7627. public function __toString()
  7628. {
  7629. // There is no $this->data here
  7630. return md5(serialize($this));
  7631. }
  7632. /**
  7633. * Get the category identifier
  7634. *
  7635. * @return string|null
  7636. */
  7637. public function get_term()
  7638. {
  7639. if ($this->term !== null)
  7640. {
  7641. return $this->term;
  7642. }
  7643. else
  7644. {
  7645. return null;
  7646. }
  7647. }
  7648. /**
  7649. * Get the categorization scheme identifier
  7650. *
  7651. * @return string|null
  7652. */
  7653. public function get_scheme()
  7654. {
  7655. if ($this->scheme !== null)
  7656. {
  7657. return $this->scheme;
  7658. }
  7659. else
  7660. {
  7661. return null;
  7662. }
  7663. }
  7664. /**
  7665. * Get the human readable label
  7666. *
  7667. * @return string|null
  7668. */
  7669. public function get_label()
  7670. {
  7671. if ($this->label !== null)
  7672. {
  7673. return $this->label;
  7674. }
  7675. else
  7676. {
  7677. return $this->get_term();
  7678. }
  7679. }
  7680. }
  7681. /**
  7682. * Handles `<media:text>` captions as defined in Media RSS.
  7683. *
  7684. * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
  7685. *
  7686. * This class can be overloaded with {@see SimplePie::set_caption_class()}
  7687. *
  7688. * @package SimplePie
  7689. * @subpackage API
  7690. */
  7691. class SimplePie_Caption
  7692. {
  7693. /**
  7694. * Content type
  7695. *
  7696. * @var string
  7697. * @see get_type()
  7698. */
  7699. var $type;
  7700. /**
  7701. * Language
  7702. *
  7703. * @var string
  7704. * @see get_language()
  7705. */
  7706. var $lang;
  7707. /**
  7708. * Start time
  7709. *
  7710. * @var string
  7711. * @see get_starttime()
  7712. */
  7713. var $startTime;
  7714. /**
  7715. * End time
  7716. *
  7717. * @var string
  7718. * @see get_endtime()
  7719. */
  7720. var $endTime;
  7721. /**
  7722. * Caption text
  7723. *
  7724. * @var string
  7725. * @see get_text()
  7726. */
  7727. var $text;
  7728. /**
  7729. * Constructor, used to input the data
  7730. *
  7731. * For documentation on all the parameters, see the corresponding
  7732. * properties and their accessors
  7733. */
  7734. public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
  7735. {
  7736. $this->type = $type;
  7737. $this->lang = $lang;
  7738. $this->startTime = $startTime;
  7739. $this->endTime = $endTime;
  7740. $this->text = $text;
  7741. }
  7742. /**
  7743. * String-ified version
  7744. *
  7745. * @return string
  7746. */
  7747. public function __toString()
  7748. {
  7749. // There is no $this->data here
  7750. return md5(serialize($this));
  7751. }
  7752. /**
  7753. * Get the end time
  7754. *
  7755. * @return string|null Time in the format 'hh:mm:ss.SSS'
  7756. */
  7757. public function get_endtime()
  7758. {
  7759. if ($this->endTime !== null)
  7760. {
  7761. return $this->endTime;
  7762. }
  7763. else
  7764. {
  7765. return null;
  7766. }
  7767. }
  7768. /**
  7769. * Get the language
  7770. *
  7771. * @link http://tools.ietf.org/html/rfc3066
  7772. * @return string|null Language code as per RFC 3066
  7773. */
  7774. public function get_language()
  7775. {
  7776. if ($this->lang !== null)
  7777. {
  7778. return $this->lang;
  7779. }
  7780. else
  7781. {
  7782. return null;
  7783. }
  7784. }
  7785. /**
  7786. * Get the start time
  7787. *
  7788. * @return string|null Time in the format 'hh:mm:ss.SSS'
  7789. */
  7790. public function get_starttime()
  7791. {
  7792. if ($this->startTime !== null)
  7793. {
  7794. return $this->startTime;
  7795. }
  7796. else
  7797. {
  7798. return null;
  7799. }
  7800. }
  7801. /**
  7802. * Get the text of the caption
  7803. *
  7804. * @return string|null
  7805. */
  7806. public function get_text()
  7807. {
  7808. if ($this->text !== null)
  7809. {
  7810. return $this->text;
  7811. }
  7812. else
  7813. {
  7814. return null;
  7815. }
  7816. }
  7817. /**
  7818. * Get the content type (not MIME type)
  7819. *
  7820. * @return string|null Either 'text' or 'html'
  7821. */
  7822. public function get_type()
  7823. {
  7824. if ($this->type !== null)
  7825. {
  7826. return $this->type;
  7827. }
  7828. else
  7829. {
  7830. return null;
  7831. }
  7832. }
  7833. }
  7834. /**
  7835. * Date Parser
  7836. *
  7837. * @package SimplePie
  7838. * @subpackage Parsing
  7839. */
  7840. class SimplePie_Parse_Date
  7841. {
  7842. /**
  7843. * Input data
  7844. *
  7845. * @access protected
  7846. * @var string
  7847. */
  7848. var $date;
  7849. /**
  7850. * List of days, calendar day name => ordinal day number in the week
  7851. *
  7852. * @access protected
  7853. * @var array
  7854. */
  7855. var $day = array(
  7856. // English
  7857. 'mon' => 1,
  7858. 'monday' => 1,
  7859. 'tue' => 2,
  7860. 'tuesday' => 2,
  7861. 'wed' => 3,
  7862. 'wednesday' => 3,
  7863. 'thu' => 4,
  7864. 'thursday' => 4,
  7865. 'fri' => 5,
  7866. 'friday' => 5,
  7867. 'sat' => 6,
  7868. 'saturday' => 6,
  7869. 'sun' => 7,
  7870. 'sunday' => 7,
  7871. // Dutch
  7872. 'maandag' => 1,
  7873. 'dinsdag' => 2,
  7874. 'woensdag' => 3,
  7875. 'donderdag' => 4,
  7876. 'vrijdag' => 5,
  7877. 'zaterdag' => 6,
  7878. 'zondag' => 7,
  7879. // French
  7880. 'lundi' => 1,
  7881. 'mardi' => 2,
  7882. 'mercredi' => 3,
  7883. 'jeudi' => 4,
  7884. 'vendredi' => 5,
  7885. 'samedi' => 6,
  7886. 'dimanche' => 7,
  7887. // German
  7888. 'montag' => 1,
  7889. 'dienstag' => 2,
  7890. 'mittwoch' => 3,
  7891. 'donnerstag' => 4,
  7892. 'freitag' => 5,
  7893. 'samstag' => 6,
  7894. 'sonnabend' => 6,
  7895. 'sonntag' => 7,
  7896. // Italian
  7897. 'lunedì' => 1,
  7898. 'martedì' => 2,
  7899. 'mercoledì' => 3,
  7900. 'giovedì' => 4,
  7901. 'venerdì' => 5,
  7902. 'sabato' => 6,
  7903. 'domenica' => 7,
  7904. // Spanish
  7905. 'lunes' => 1,
  7906. 'martes' => 2,
  7907. 'miércoles' => 3,
  7908. 'jueves' => 4,
  7909. 'viernes' => 5,
  7910. 'sábado' => 6,
  7911. 'domingo' => 7,
  7912. // Finnish
  7913. 'maanantai' => 1,
  7914. 'tiistai' => 2,
  7915. 'keskiviikko' => 3,
  7916. 'torstai' => 4,
  7917. 'perjantai' => 5,
  7918. 'lauantai' => 6,
  7919. 'sunnuntai' => 7,
  7920. // Hungarian
  7921. 'hétfő' => 1,
  7922. 'kedd' => 2,
  7923. 'szerda' => 3,
  7924. 'csütörtok' => 4,
  7925. 'péntek' => 5,
  7926. 'szombat' => 6,
  7927. 'vasárnap' => 7,
  7928. // Greek
  7929. 'Δευ' => 1,
  7930. 'Τρι' => 2,
  7931. 'Τετ' => 3,
  7932. 'Πεμ' => 4,
  7933. 'Παρ' => 5,
  7934. 'Σαβ' => 6,
  7935. 'Κυρ' => 7,
  7936. );
  7937. /**
  7938. * List of months, calendar month name => calendar month number
  7939. *
  7940. * @access protected
  7941. * @var array
  7942. */
  7943. var $month = array(
  7944. // English
  7945. 'jan' => 1,
  7946. 'january' => 1,
  7947. 'feb' => 2,
  7948. 'february' => 2,
  7949. 'mar' => 3,
  7950. 'march' => 3,
  7951. 'apr' => 4,
  7952. 'april' => 4,
  7953. 'may' => 5,
  7954. // No long form of May
  7955. 'jun' => 6,
  7956. 'june' => 6,
  7957. 'jul' => 7,
  7958. 'july' => 7,
  7959. 'aug' => 8,
  7960. 'august' => 8,
  7961. 'sep' => 9,
  7962. 'september' => 8,
  7963. 'oct' => 10,
  7964. 'october' => 10,
  7965. 'nov' => 11,
  7966. 'november' => 11,
  7967. 'dec' => 12,
  7968. 'december' => 12,
  7969. // Dutch
  7970. 'januari' => 1,
  7971. 'februari' => 2,
  7972. 'maart' => 3,
  7973. 'april' => 4,
  7974. 'mei' => 5,
  7975. 'juni' => 6,
  7976. 'juli' => 7,
  7977. 'augustus' => 8,
  7978. 'september' => 9,
  7979. 'oktober' => 10,
  7980. 'november' => 11,
  7981. 'december' => 12,
  7982. // French
  7983. 'janvier' => 1,
  7984. 'février' => 2,
  7985. 'mars' => 3,
  7986. 'avril' => 4,
  7987. 'mai' => 5,
  7988. 'juin' => 6,
  7989. 'juillet' => 7,
  7990. 'août' => 8,
  7991. 'septembre' => 9,
  7992. 'octobre' => 10,
  7993. 'novembre' => 11,
  7994. 'décembre' => 12,
  7995. // German
  7996. 'januar' => 1,
  7997. 'februar' => 2,
  7998. 'märz' => 3,
  7999. 'april' => 4,
  8000. 'mai' => 5,
  8001. 'juni' => 6,
  8002. 'juli' => 7,
  8003. 'august' => 8,
  8004. 'september' => 9,
  8005. 'oktober' => 10,
  8006. 'november' => 11,
  8007. 'dezember' => 12,
  8008. // Italian
  8009. 'gennaio' => 1,
  8010. 'febbraio' => 2,
  8011. 'marzo' => 3,
  8012. 'aprile' => 4,
  8013. 'maggio' => 5,
  8014. 'giugno' => 6,
  8015. 'luglio' => 7,
  8016. 'agosto' => 8,
  8017. 'settembre' => 9,
  8018. 'ottobre' => 10,
  8019. 'novembre' => 11,
  8020. 'dicembre' => 12,
  8021. // Spanish
  8022. 'enero' => 1,
  8023. 'febrero' => 2,
  8024. 'marzo' => 3,
  8025. 'abril' => 4,
  8026. 'mayo' => 5,
  8027. 'junio' => 6,
  8028. 'julio' => 7,
  8029. 'agosto' => 8,
  8030. 'septiembre' => 9,
  8031. 'setiembre' => 9,
  8032. 'octubre' => 10,
  8033. 'noviembre' => 11,
  8034. 'diciembre' => 12,
  8035. // Finnish
  8036. 'tammikuu' => 1,
  8037. 'helmikuu' => 2,
  8038. 'maaliskuu' => 3,
  8039. 'huhtikuu' => 4,
  8040. 'toukokuu' => 5,
  8041. 'kesäkuu' => 6,
  8042. 'heinäkuu' => 7,
  8043. 'elokuu' => 8,
  8044. 'suuskuu' => 9,
  8045. 'lokakuu' => 10,
  8046. 'marras' => 11,
  8047. 'joulukuu' => 12,
  8048. // Hungarian
  8049. 'január' => 1,
  8050. 'február' => 2,
  8051. 'március' => 3,
  8052. 'április' => 4,
  8053. 'május' => 5,
  8054. 'június' => 6,
  8055. 'július' => 7,
  8056. 'augusztus' => 8,
  8057. 'szeptember' => 9,
  8058. 'október' => 10,
  8059. 'november' => 11,
  8060. 'december' => 12,
  8061. // Greek
  8062. 'Ιαν' => 1,
  8063. 'Φεβ' => 2,
  8064. 'Μάώ' => 3,
  8065. 'Μαώ' => 3,
  8066. 'Απρ' => 4,
  8067. 'Μάι' => 5,
  8068. 'Μαϊ' => 5,
  8069. 'Μαι' => 5,
  8070. 'Ιούν' => 6,
  8071. 'Ιον' => 6,
  8072. 'Ιούλ' => 7,
  8073. 'Ιολ' => 7,
  8074. 'Αύγ' => 8,
  8075. 'Αυγ' => 8,
  8076. 'Σεπ' => 9,
  8077. 'Οκτ' => 10,
  8078. 'Νοέ' => 11,
  8079. 'Δεκ' => 12,
  8080. );
  8081. /**
  8082. * List of timezones, abbreviation => offset from UTC
  8083. *
  8084. * @access protected
  8085. * @var array
  8086. */
  8087. var $timezone = array(
  8088. 'ACDT' => 37800,
  8089. 'ACIT' => 28800,
  8090. 'ACST' => 34200,
  8091. 'ACT' => -18000,
  8092. 'ACWDT' => 35100,
  8093. 'ACWST' => 31500,
  8094. 'AEDT' => 39600,
  8095. 'AEST' => 36000,
  8096. 'AFT' => 16200,
  8097. 'AKDT' => -28800,
  8098. 'AKST' => -32400,
  8099. 'AMDT' => 18000,
  8100. 'AMT' => -14400,
  8101. 'ANAST' => 46800,
  8102. 'ANAT' => 43200,
  8103. 'ART' => -10800,
  8104. 'AZOST' => -3600,
  8105. 'AZST' => 18000,
  8106. 'AZT' => 14400,
  8107. 'BIOT' => 21600,
  8108. 'BIT' => -43200,
  8109. 'BOT' => -14400,
  8110. 'BRST' => -7200,
  8111. 'BRT' => -10800,
  8112. 'BST' => 3600,
  8113. 'BTT' => 21600,
  8114. 'CAST' => 18000,
  8115. 'CAT' => 7200,
  8116. 'CCT' => 23400,
  8117. 'CDT' => -18000,
  8118. 'CEDT' => 7200,
  8119. 'CET' => 3600,
  8120. 'CGST' => -7200,
  8121. 'CGT' => -10800,
  8122. 'CHADT' => 49500,
  8123. 'CHAST' => 45900,
  8124. 'CIST' => -28800,
  8125. 'CKT' => -36000,
  8126. 'CLDT' => -10800,
  8127. 'CLST' => -14400,
  8128. 'COT' => -18000,
  8129. 'CST' => -21600,
  8130. 'CVT' => -3600,
  8131. 'CXT' => 25200,
  8132. 'DAVT' => 25200,
  8133. 'DTAT' => 36000,
  8134. 'EADT' => -18000,
  8135. 'EAST' => -21600,
  8136. 'EAT' => 10800,
  8137. 'ECT' => -18000,
  8138. 'EDT' => -14400,
  8139. 'EEST' => 10800,
  8140. 'EET' => 7200,
  8141. 'EGT' => -3600,
  8142. 'EKST' => 21600,
  8143. 'EST' => -18000,
  8144. 'FJT' => 43200,
  8145. 'FKDT' => -10800,
  8146. 'FKST' => -14400,
  8147. 'FNT' => -7200,
  8148. 'GALT' => -21600,
  8149. 'GEDT' => 14400,
  8150. 'GEST' => 10800,
  8151. 'GFT' => -10800,
  8152. 'GILT' => 43200,
  8153. 'GIT' => -32400,
  8154. 'GST' => 14400,
  8155. 'GST' => -7200,
  8156. 'GYT' => -14400,
  8157. 'HAA' => -10800,
  8158. 'HAC' => -18000,
  8159. 'HADT' => -32400,
  8160. 'HAE' => -14400,
  8161. 'HAP' => -25200,
  8162. 'HAR' => -21600,
  8163. 'HAST' => -36000,
  8164. 'HAT' => -9000,
  8165. 'HAY' => -28800,
  8166. 'HKST' => 28800,
  8167. 'HMT' => 18000,
  8168. 'HNA' => -14400,
  8169. 'HNC' => -21600,
  8170. 'HNE' => -18000,
  8171. 'HNP' => -28800,
  8172. 'HNR' => -25200,
  8173. 'HNT' => -12600,
  8174. 'HNY' => -32400,
  8175. 'IRDT' => 16200,
  8176. 'IRKST' => 32400,
  8177. 'IRKT' => 28800,
  8178. 'IRST' => 12600,
  8179. 'JFDT' => -10800,
  8180. 'JFST' => -14400,
  8181. 'JST' => 32400,
  8182. 'KGST' => 21600,
  8183. 'KGT' => 18000,
  8184. 'KOST' => 39600,
  8185. 'KOVST' => 28800,
  8186. 'KOVT' => 25200,
  8187. 'KRAST' => 28800,
  8188. 'KRAT' => 25200,
  8189. 'KST' => 32400,
  8190. 'LHDT' => 39600,
  8191. 'LHST' => 37800,
  8192. 'LINT' => 50400,
  8193. 'LKT' => 21600,
  8194. 'MAGST' => 43200,
  8195. 'MAGT' => 39600,
  8196. 'MAWT' => 21600,
  8197. 'MDT' => -21600,
  8198. 'MESZ' => 7200,
  8199. 'MEZ' => 3600,
  8200. 'MHT' => 43200,
  8201. 'MIT' => -34200,
  8202. 'MNST' => 32400,
  8203. 'MSDT' => 14400,
  8204. 'MSST' => 10800,
  8205. 'MST' => -25200,
  8206. 'MUT' => 14400,
  8207. 'MVT' => 18000,
  8208. 'MYT' => 28800,
  8209. 'NCT' => 39600,
  8210. 'NDT' => -9000,
  8211. 'NFT' => 41400,
  8212. 'NMIT' => 36000,
  8213. 'NOVST' => 25200,
  8214. 'NOVT' => 21600,
  8215. 'NPT' => 20700,
  8216. 'NRT' => 43200,
  8217. 'NST' => -12600,
  8218. 'NUT' => -39600,
  8219. 'NZDT' => 46800,
  8220. 'NZST' => 43200,
  8221. 'OMSST' => 25200,
  8222. 'OMST' => 21600,
  8223. 'PDT' => -25200,
  8224. 'PET' => -18000,
  8225. 'PETST' => 46800,
  8226. 'PETT' => 43200,
  8227. 'PGT' => 36000,
  8228. 'PHOT' => 46800,
  8229. 'PHT' => 28800,
  8230. 'PKT' => 18000,
  8231. 'PMDT' => -7200,
  8232. 'PMST' => -10800,
  8233. 'PONT' => 39600,
  8234. 'PST' => -28800,
  8235. 'PWT' => 32400,
  8236. 'PYST' => -10800,
  8237. 'PYT' => -14400,
  8238. 'RET' => 14400,
  8239. 'ROTT' => -10800,
  8240. 'SAMST' => 18000,
  8241. 'SAMT' => 14400,
  8242. 'SAST' => 7200,
  8243. 'SBT' => 39600,
  8244. 'SCDT' => 46800,
  8245. 'SCST' => 43200,
  8246. 'SCT' => 14400,
  8247. 'SEST' => 3600,
  8248. 'SGT' => 28800,
  8249. 'SIT' => 28800,
  8250. 'SRT' => -10800,
  8251. 'SST' => -39600,
  8252. 'SYST' => 10800,
  8253. 'SYT' => 7200,
  8254. 'TFT' => 18000,
  8255. 'THAT' => -36000,
  8256. 'TJT' => 18000,
  8257. 'TKT' => -36000,
  8258. 'TMT' => 18000,
  8259. 'TOT' => 46800,
  8260. 'TPT' => 32400,
  8261. 'TRUT' => 36000,
  8262. 'TVT' => 43200,
  8263. 'TWT' => 28800,
  8264. 'UYST' => -7200,
  8265. 'UYT' => -10800,
  8266. 'UZT' => 18000,
  8267. 'VET' => -14400,
  8268. 'VLAST' => 39600,
  8269. 'VLAT' => 36000,
  8270. 'VOST' => 21600,
  8271. 'VUT' => 39600,
  8272. 'WAST' => 7200,
  8273. 'WAT' => 3600,
  8274. 'WDT' => 32400,
  8275. 'WEST' => 3600,
  8276. 'WFT' => 43200,
  8277. 'WIB' => 25200,
  8278. 'WIT' => 32400,
  8279. 'WITA' => 28800,
  8280. 'WKST' => 18000,
  8281. 'WST' => 28800,
  8282. 'YAKST' => 36000,
  8283. 'YAKT' => 32400,
  8284. 'YAPT' => 36000,
  8285. 'YEKST' => 21600,
  8286. 'YEKT' => 18000,
  8287. );
  8288. /**
  8289. * Cached PCRE for SimplePie_Parse_Date::$day
  8290. *
  8291. * @access protected
  8292. * @var string
  8293. */
  8294. var $day_pcre;
  8295. /**
  8296. * Cached PCRE for SimplePie_Parse_Date::$month
  8297. *
  8298. * @access protected
  8299. * @var string
  8300. */
  8301. var $month_pcre;
  8302. /**
  8303. * Array of user-added callback methods
  8304. *
  8305. * @access private
  8306. * @var array
  8307. */
  8308. var $built_in = array();
  8309. /**
  8310. * Array of user-added callback methods
  8311. *
  8312. * @access private
  8313. * @var array
  8314. */
  8315. var $user = array();
  8316. /**
  8317. * Create new SimplePie_Parse_Date object, and set self::day_pcre,
  8318. * self::month_pcre, and self::built_in
  8319. *
  8320. * @access private
  8321. */
  8322. public function __construct()
  8323. {
  8324. $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
  8325. $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
  8326. static $cache;
  8327. if (!isset($cache[get_class($this)]))
  8328. {
  8329. $all_methods = get_class_methods($this);
  8330. foreach ($all_methods as $method)
  8331. {
  8332. if (strtolower(substr($method, 0, 5)) === 'date_')
  8333. {
  8334. $cache[get_class($this)][] = $method;
  8335. }
  8336. }
  8337. }
  8338. foreach ($cache[get_class($this)] as $method)
  8339. {
  8340. $this->built_in[] = $method;
  8341. }
  8342. }
  8343. /**
  8344. * Get the object
  8345. *
  8346. * @access public
  8347. */
  8348. public static function get()
  8349. {
  8350. static $object;
  8351. if (!$object)
  8352. {
  8353. $object = new SimplePie_Parse_Date;
  8354. }
  8355. return $object;
  8356. }
  8357. /**
  8358. * Parse a date
  8359. *
  8360. * @final
  8361. * @access public
  8362. * @param string $date Date to parse
  8363. * @return int Timestamp corresponding to date string, or false on failure
  8364. */
  8365. public function parse($date)
  8366. {
  8367. foreach ($this->user as $method)
  8368. {
  8369. if (($returned = call_user_func($method, $date)) !== false)
  8370. {
  8371. return $returned;
  8372. }
  8373. }
  8374. foreach ($this->built_in as $method)
  8375. {
  8376. if (($returned = call_user_func(array($this, $method), $date)) !== false)
  8377. {
  8378. return $returned;
  8379. }
  8380. }
  8381. return false;
  8382. }
  8383. /**
  8384. * Add a callback method to parse a date
  8385. *
  8386. * @final
  8387. * @access public
  8388. * @param callback $callback
  8389. */
  8390. public function add_callback($callback)
  8391. {
  8392. if (is_callable($callback))
  8393. {
  8394. $this->user[] = $callback;
  8395. }
  8396. else
  8397. {
  8398. trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
  8399. }
  8400. }
  8401. /**
  8402. * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
  8403. * well as allowing any of upper or lower case "T", horizontal tabs, or
  8404. * spaces to be used as the time seperator (including more than one))
  8405. *
  8406. * @access protected
  8407. * @return int Timestamp
  8408. */
  8409. public function date_w3cdtf($date)
  8410. {
  8411. static $pcre;
  8412. if (!$pcre)
  8413. {
  8414. $year = '([0-9]{4})';
  8415. $month = $day = $hour = $minute = $second = '([0-9]{2})';
  8416. $decimal = '([0-9]*)';
  8417. $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
  8418. $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
  8419. }
  8420. if (preg_match($pcre, $date, $match))
  8421. {
  8422. /*
  8423. Capturing subpatterns:
  8424. 1: Year
  8425. 2: Month
  8426. 3: Day
  8427. 4: Hour
  8428. 5: Minute
  8429. 6: Second
  8430. 7: Decimal fraction of a second
  8431. 8: Zulu
  8432. 9: Timezone ±
  8433. 10: Timezone hours
  8434. 11: Timezone minutes
  8435. */
  8436. // Fill in empty matches
  8437. for ($i = count($match); $i <= 3; $i++)
  8438. {
  8439. $match[$i] = '1';
  8440. }
  8441. for ($i = count($match); $i <= 7; $i++)
  8442. {
  8443. $match[$i] = '0';
  8444. }
  8445. // Numeric timezone
  8446. if (isset($match[9]) && $match[9] !== '')
  8447. {
  8448. $timezone = $match[10] * 3600;
  8449. $timezone += $match[11] * 60;
  8450. if ($match[9] === '-')
  8451. {
  8452. $timezone = 0 - $timezone;
  8453. }
  8454. }
  8455. else
  8456. {
  8457. $timezone = 0;
  8458. }
  8459. // Convert the number of seconds to an integer, taking decimals into account
  8460. $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
  8461. return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
  8462. }
  8463. else
  8464. {
  8465. return false;
  8466. }
  8467. }
  8468. /**
  8469. * Remove RFC822 comments
  8470. *
  8471. * @access protected
  8472. * @param string $data Data to strip comments from
  8473. * @return string Comment stripped string
  8474. */
  8475. public function remove_rfc2822_comments($string)
  8476. {
  8477. $string = (string) $string;
  8478. $position = 0;
  8479. $length = strlen($string);
  8480. $depth = 0;
  8481. $output = '';
  8482. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  8483. {
  8484. $output .= substr($string, $position, $pos - $position);
  8485. $position = $pos + 1;
  8486. if ($string[$pos - 1] !== '\\')
  8487. {
  8488. $depth++;
  8489. while ($depth && $position < $length)
  8490. {
  8491. $position += strcspn($string, '()', $position);
  8492. if ($string[$position - 1] === '\\')
  8493. {
  8494. $position++;
  8495. continue;
  8496. }
  8497. elseif (isset($string[$position]))
  8498. {
  8499. switch ($string[$position])
  8500. {
  8501. case '(':
  8502. $depth++;
  8503. break;
  8504. case ')':
  8505. $depth--;
  8506. break;
  8507. }
  8508. $position++;
  8509. }
  8510. else
  8511. {
  8512. break;
  8513. }
  8514. }
  8515. }
  8516. else
  8517. {
  8518. $output .= '(';
  8519. }
  8520. }
  8521. $output .= substr($string, $position);
  8522. return $output;
  8523. }
  8524. /**
  8525. * Parse RFC2822's date format
  8526. *
  8527. * @access protected
  8528. * @return int Timestamp
  8529. */
  8530. public function date_rfc2822($date)
  8531. {
  8532. static $pcre;
  8533. if (!$pcre)
  8534. {
  8535. $wsp = '[\x09\x20]';
  8536. $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
  8537. $optional_fws = $fws . '?';
  8538. $day_name = $this->day_pcre;
  8539. $month = $this->month_pcre;
  8540. $day = '([0-9]{1,2})';
  8541. $hour = $minute = $second = '([0-9]{2})';
  8542. $year = '([0-9]{2,4})';
  8543. $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
  8544. $character_zone = '([A-Z]{1,5})';
  8545. $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
  8546. $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';
  8547. }
  8548. if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
  8549. {
  8550. /*
  8551. Capturing subpatterns:
  8552. 1: Day name
  8553. 2: Day
  8554. 3: Month
  8555. 4: Year
  8556. 5: Hour
  8557. 6: Minute
  8558. 7: Second
  8559. 8: Timezone ±
  8560. 9: Timezone hours
  8561. 10: Timezone minutes
  8562. 11: Alphabetic timezone
  8563. */
  8564. // Find the month number
  8565. $month = $this->month[strtolower($match[3])];
  8566. // Numeric timezone
  8567. if ($match[8] !== '')
  8568. {
  8569. $timezone = $match[9] * 3600;
  8570. $timezone += $match[10] * 60;
  8571. if ($match[8] === '-')
  8572. {
  8573. $timezone = 0 - $timezone;
  8574. }
  8575. }
  8576. // Character timezone
  8577. elseif (isset($this->timezone[strtoupper($match[11])]))
  8578. {
  8579. $timezone = $this->timezone[strtoupper($match[11])];
  8580. }
  8581. // Assume everything else to be -0000
  8582. else
  8583. {
  8584. $timezone = 0;
  8585. }
  8586. // Deal with 2/3 digit years
  8587. if ($match[4] < 50)
  8588. {
  8589. $match[4] += 2000;
  8590. }
  8591. elseif ($match[4] < 1000)
  8592. {
  8593. $match[4] += 1900;
  8594. }
  8595. // Second is optional, if it is empty set it to zero
  8596. if ($match[7] !== '')
  8597. {
  8598. $second = $match[7];
  8599. }
  8600. else
  8601. {
  8602. $second = 0;
  8603. }
  8604. return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
  8605. }
  8606. else
  8607. {
  8608. return false;
  8609. }
  8610. }
  8611. /**
  8612. * Parse RFC850's date format
  8613. *
  8614. * @access protected
  8615. * @return int Timestamp
  8616. */
  8617. public function date_rfc850($date)
  8618. {
  8619. static $pcre;
  8620. if (!$pcre)
  8621. {
  8622. $space = '[\x09\x20]+';
  8623. $day_name = $this->day_pcre;
  8624. $month = $this->month_pcre;
  8625. $day = '([0-9]{1,2})';
  8626. $year = $hour = $minute = $second = '([0-9]{2})';
  8627. $zone = '([A-Z]{1,5})';
  8628. $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
  8629. }
  8630. if (preg_match($pcre, $date, $match))
  8631. {
  8632. /*
  8633. Capturing subpatterns:
  8634. 1: Day name
  8635. 2: Day
  8636. 3: Month
  8637. 4: Year
  8638. 5: Hour
  8639. 6: Minute
  8640. 7: Second
  8641. 8: Timezone
  8642. */
  8643. // Month
  8644. $month = $this->month[strtolower($match[3])];
  8645. // Character timezone
  8646. if (isset($this->timezone[strtoupper($match[8])]))
  8647. {
  8648. $timezone = $this->timezone[strtoupper($match[8])];
  8649. }
  8650. // Assume everything else to be -0000
  8651. else
  8652. {
  8653. $timezone = 0;
  8654. }
  8655. // Deal with 2 digit year
  8656. if ($match[4] < 50)
  8657. {
  8658. $match[4] += 2000;
  8659. }
  8660. else
  8661. {
  8662. $match[4] += 1900;
  8663. }
  8664. return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
  8665. }
  8666. else
  8667. {
  8668. return false;
  8669. }
  8670. }
  8671. /**
  8672. * Parse C99's asctime()'s date format
  8673. *
  8674. * @access protected
  8675. * @return int Timestamp
  8676. */
  8677. public function date_asctime($date)
  8678. {
  8679. static $pcre;
  8680. if (!$pcre)
  8681. {
  8682. $space = '[\x09\x20]+';
  8683. $wday_name = $this->day_pcre;
  8684. $mon_name = $this->month_pcre;
  8685. $day = '([0-9]{1,2})';
  8686. $hour = $sec = $min = '([0-9]{2})';
  8687. $year = '([0-9]{4})';
  8688. $terminator = '\x0A?\x00?';
  8689. $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
  8690. }
  8691. if (preg_match($pcre, $date, $match))
  8692. {
  8693. /*
  8694. Capturing subpatterns:
  8695. 1: Day name
  8696. 2: Month
  8697. 3: Day
  8698. 4: Hour
  8699. 5: Minute
  8700. 6: Second
  8701. 7: Year
  8702. */
  8703. $month = $this->month[strtolower($match[2])];
  8704. return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
  8705. }
  8706. else
  8707. {
  8708. return false;
  8709. }
  8710. }
  8711. /**
  8712. * Parse dates using strtotime()
  8713. *
  8714. * @access protected
  8715. * @return int Timestamp
  8716. */
  8717. public function date_strtotime($date)
  8718. {
  8719. $strtotime = strtotime($date);
  8720. if ($strtotime === -1 || $strtotime === false)
  8721. {
  8722. return false;
  8723. }
  8724. else
  8725. {
  8726. return $strtotime;
  8727. }
  8728. }
  8729. }
  8730. /**
  8731. * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
  8732. *
  8733. * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
  8734. *
  8735. * This class can be overloaded with {@see SimplePie::set_rating_class()}
  8736. *
  8737. * @package SimplePie
  8738. * @subpackage API
  8739. */
  8740. class SimplePie_Rating
  8741. {
  8742. /**
  8743. * Rating scheme
  8744. *
  8745. * @var string
  8746. * @see get_scheme()
  8747. */
  8748. var $scheme;
  8749. /**
  8750. * Rating value
  8751. *
  8752. * @var string
  8753. * @see get_value()
  8754. */
  8755. var $value;
  8756. /**
  8757. * Constructor, used to input the data
  8758. *
  8759. * For documentation on all the parameters, see the corresponding
  8760. * properties and their accessors
  8761. */
  8762. public function __construct($scheme = null, $value = null)
  8763. {
  8764. $this->scheme = $scheme;
  8765. $this->value = $value;
  8766. }
  8767. /**
  8768. * String-ified version
  8769. *
  8770. * @return string
  8771. */
  8772. public function __toString()
  8773. {
  8774. // There is no $this->data here
  8775. return md5(serialize($this));
  8776. }
  8777. /**
  8778. * Get the organizational scheme for the rating
  8779. *
  8780. * @return string|null
  8781. */
  8782. public function get_scheme()
  8783. {
  8784. if ($this->scheme !== null)
  8785. {
  8786. return $this->scheme;
  8787. }
  8788. else
  8789. {
  8790. return null;
  8791. }
  8792. }
  8793. /**
  8794. * Get the value of the rating
  8795. *
  8796. * @return string|null
  8797. */
  8798. public function get_value()
  8799. {
  8800. if ($this->value !== null)
  8801. {
  8802. return $this->value;
  8803. }
  8804. else
  8805. {
  8806. return null;
  8807. }
  8808. }
  8809. }
  8810. /**
  8811. * Manages all author-related data
  8812. *
  8813. * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
  8814. *
  8815. * This class can be overloaded with {@see SimplePie::set_author_class()}
  8816. *
  8817. * @package SimplePie
  8818. * @subpackage API
  8819. */
  8820. class SimplePie_Author
  8821. {
  8822. /**
  8823. * Author's name
  8824. *
  8825. * @var string
  8826. * @see get_name()
  8827. */
  8828. var $name;
  8829. /**
  8830. * Author's link
  8831. *
  8832. * @var string
  8833. * @see get_link()
  8834. */
  8835. var $link;
  8836. /**
  8837. * Author's email address
  8838. *
  8839. * @var string
  8840. * @see get_email()
  8841. */
  8842. var $email;
  8843. /**
  8844. * Constructor, used to input the data
  8845. *
  8846. * @param string $name
  8847. * @param string $link
  8848. * @param string $email
  8849. */
  8850. public function __construct($name = null, $link = null, $email = null)
  8851. {
  8852. $this->name = $name;
  8853. $this->link = $link;
  8854. $this->email = $email;
  8855. }
  8856. /**
  8857. * String-ified version
  8858. *
  8859. * @return string
  8860. */
  8861. public function __toString()
  8862. {
  8863. // There is no $this->data here
  8864. return md5(serialize($this));
  8865. }
  8866. /**
  8867. * Author's name
  8868. *
  8869. * @return string|null
  8870. */
  8871. public function get_name()
  8872. {
  8873. if ($this->name !== null)
  8874. {
  8875. return $this->name;
  8876. }
  8877. else
  8878. {
  8879. return null;
  8880. }
  8881. }
  8882. /**
  8883. * Author's link
  8884. *
  8885. * @return string|null
  8886. */
  8887. public function get_link()
  8888. {
  8889. if ($this->link !== null)
  8890. {
  8891. return $this->link;
  8892. }
  8893. else
  8894. {
  8895. return null;
  8896. }
  8897. }
  8898. /**
  8899. * Author's email address
  8900. *
  8901. * @return string|null
  8902. */
  8903. public function get_email()
  8904. {
  8905. if ($this->email !== null)
  8906. {
  8907. return $this->email;
  8908. }
  8909. else
  8910. {
  8911. return null;
  8912. }
  8913. }
  8914. }
  8915. /**
  8916. * Content-type sniffing
  8917. *
  8918. * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
  8919. *
  8920. * This is used since we can't always trust Content-Type headers, and is based
  8921. * upon the HTML5 parsing rules.
  8922. *
  8923. *
  8924. * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
  8925. *
  8926. * @package SimplePie
  8927. * @subpackage HTTP
  8928. */
  8929. class SimplePie_Content_Type_Sniffer
  8930. {
  8931. /**
  8932. * File object
  8933. *
  8934. * @var SimplePie_File
  8935. */
  8936. var $file;
  8937. /**
  8938. * Create an instance of the class with the input file
  8939. *
  8940. * @param SimplePie_Content_Type_Sniffer $file Input file
  8941. */
  8942. public function __construct($file)
  8943. {
  8944. $this->file = $file;
  8945. }
  8946. /**
  8947. * Get the Content-Type of the specified file
  8948. *
  8949. * @return string Actual Content-Type
  8950. */
  8951. public function get_type()
  8952. {
  8953. if (isset($this->file->headers['content-type']))
  8954. {
  8955. if (!isset($this->file->headers['content-encoding'])
  8956. && ($this->file->headers['content-type'] === 'text/plain'
  8957. || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
  8958. || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
  8959. || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
  8960. {
  8961. return $this->text_or_binary();
  8962. }
  8963. if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
  8964. {
  8965. $official = substr($this->file->headers['content-type'], 0, $pos);
  8966. }
  8967. else
  8968. {
  8969. $official = $this->file->headers['content-type'];
  8970. }
  8971. $official = trim(strtolower($official));
  8972. if ($official === 'unknown/unknown'
  8973. || $official === 'application/unknown')
  8974. {
  8975. return $this->unknown();
  8976. }
  8977. elseif (substr($official, -4) === '+xml'
  8978. || $official === 'text/xml'
  8979. || $official === 'application/xml')
  8980. {
  8981. return $official;
  8982. }
  8983. elseif (substr($official, 0, 6) === 'image/')
  8984. {
  8985. if ($return = $this->image())
  8986. {
  8987. return $return;
  8988. }
  8989. else
  8990. {
  8991. return $official;
  8992. }
  8993. }
  8994. elseif ($official === 'text/html')
  8995. {
  8996. return $this->feed_or_html();
  8997. }
  8998. else
  8999. {
  9000. return $official;
  9001. }
  9002. }
  9003. else
  9004. {
  9005. return $this->unknown();
  9006. }
  9007. }
  9008. /**
  9009. * Sniff text or binary
  9010. *
  9011. * @return string Actual Content-Type
  9012. */
  9013. public function text_or_binary()
  9014. {
  9015. if (substr($this->file->body, 0, 2) === "\xFE\xFF"
  9016. || substr($this->file->body, 0, 2) === "\xFF\xFE"
  9017. || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
  9018. || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
  9019. {
  9020. return 'text/plain';
  9021. }
  9022. elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
  9023. {
  9024. return 'application/octect-stream';
  9025. }
  9026. else
  9027. {
  9028. return 'text/plain';
  9029. }
  9030. }
  9031. /**
  9032. * Sniff unknown
  9033. *
  9034. * @return string Actual Content-Type
  9035. */
  9036. public function unknown()
  9037. {
  9038. $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
  9039. if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
  9040. || strtolower(substr($this->file->body, $ws, 5)) === '<html'
  9041. || strtolower(substr($this->file->body, $ws, 7)) === '<script')
  9042. {
  9043. return 'text/html';
  9044. }
  9045. elseif (substr($this->file->body, 0, 5) === '%PDF-')
  9046. {
  9047. return 'application/pdf';
  9048. }
  9049. elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
  9050. {
  9051. return 'application/postscript';
  9052. }
  9053. elseif (substr($this->file->body, 0, 6) === 'GIF87a'
  9054. || substr($this->file->body, 0, 6) === 'GIF89a')
  9055. {
  9056. return 'image/gif';
  9057. }
  9058. elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
  9059. {
  9060. return 'image/png';
  9061. }
  9062. elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
  9063. {
  9064. return 'image/jpeg';
  9065. }
  9066. elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
  9067. {
  9068. return 'image/bmp';
  9069. }
  9070. elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
  9071. {
  9072. return 'image/vnd.microsoft.icon';
  9073. }
  9074. else
  9075. {
  9076. return $this->text_or_binary();
  9077. }
  9078. }
  9079. /**
  9080. * Sniff images
  9081. *
  9082. * @return string Actual Content-Type
  9083. */
  9084. public function image()
  9085. {
  9086. if (substr($this->file->body, 0, 6) === 'GIF87a'
  9087. || substr($this->file->body, 0, 6) === 'GIF89a')
  9088. {
  9089. return 'image/gif';
  9090. }
  9091. elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
  9092. {
  9093. return 'image/png';
  9094. }
  9095. elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
  9096. {
  9097. return 'image/jpeg';
  9098. }
  9099. elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
  9100. {
  9101. return 'image/bmp';
  9102. }
  9103. elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
  9104. {
  9105. return 'image/vnd.microsoft.icon';
  9106. }
  9107. else
  9108. {
  9109. return false;
  9110. }
  9111. }
  9112. /**
  9113. * Sniff HTML
  9114. *
  9115. * @return string Actual Content-Type
  9116. */
  9117. public function feed_or_html()
  9118. {
  9119. $len = strlen($this->file->body);
  9120. $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
  9121. while ($pos < $len)
  9122. {
  9123. switch ($this->file->body[$pos])
  9124. {
  9125. case "\x09":
  9126. case "\x0A":
  9127. case "\x0D":
  9128. case "\x20":
  9129. $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
  9130. continue 2;
  9131. case '<':
  9132. $pos++;
  9133. break;
  9134. default:
  9135. return 'text/html';
  9136. }
  9137. if (substr($this->file->body, $pos, 3) === '!--')
  9138. {
  9139. $pos += 3;
  9140. if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
  9141. {
  9142. $pos += 3;
  9143. }
  9144. else
  9145. {
  9146. return 'text/html';
  9147. }
  9148. }
  9149. elseif (substr($this->file->body, $pos, 1) === '!')
  9150. {
  9151. if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
  9152. {
  9153. $pos++;
  9154. }
  9155. else
  9156. {
  9157. return 'text/html';
  9158. }
  9159. }
  9160. elseif (substr($this->file->body, $pos, 1) === '?')
  9161. {
  9162. if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
  9163. {
  9164. $pos += 2;
  9165. }
  9166. else
  9167. {
  9168. return 'text/html';
  9169. }
  9170. }
  9171. elseif (substr($this->file->body, $pos, 3) === 'rss'
  9172. || substr($this->file->body, $pos, 7) === 'rdf:RDF')
  9173. {
  9174. return 'application/rss+xml';
  9175. }
  9176. elseif (substr($this->file->body, $pos, 4) === 'feed')
  9177. {
  9178. return 'application/atom+xml';
  9179. }
  9180. else
  9181. {
  9182. return 'text/html';
  9183. }
  9184. }
  9185. return 'text/html';
  9186. }
  9187. }
  9188. /**
  9189. * Used for feed auto-discovery
  9190. *
  9191. *
  9192. * This class can be overloaded with {@see SimplePie::set_locator_class()}
  9193. *
  9194. * @package SimplePie
  9195. */
  9196. class SimplePie_Locator
  9197. {
  9198. var $useragent;
  9199. var $timeout;
  9200. var $file;
  9201. var $local = array();
  9202. var $elsewhere = array();
  9203. var $cached_entities = array();
  9204. var $http_base;
  9205. var $base;
  9206. var $base_location = 0;
  9207. var $checked_feeds = 0;
  9208. var $max_checked_feeds = 10;
  9209. protected $registry;
  9210. public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
  9211. {
  9212. $this->file = $file;
  9213. $this->useragent = $useragent;
  9214. $this->timeout = $timeout;
  9215. $this->max_checked_feeds = $max_checked_feeds;
  9216. if (class_exists('DOMDocument'))
  9217. {
  9218. $this->dom = new DOMDocument();
  9219. set_error_handler(array('SimplePie_Misc', 'silence_errors'));
  9220. $this->dom->loadHTML($this->file->body);
  9221. restore_error_handler();
  9222. }
  9223. else
  9224. {
  9225. $this->dom = null;
  9226. }
  9227. }
  9228. public function set_registry(SimplePie_Registry $registry)
  9229. {
  9230. $this->registry = $registry;
  9231. }
  9232. public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
  9233. {
  9234. if ($this->is_feed($this->file))
  9235. {
  9236. return $this->file;
  9237. }
  9238. if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
  9239. {
  9240. $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
  9241. if ($sniffer->get_type() !== 'text/html')
  9242. {
  9243. return null;
  9244. }
  9245. }
  9246. if ($type & ~SIMPLEPIE_LOCATOR_NONE)
  9247. {
  9248. $this->get_base();
  9249. }
  9250. if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
  9251. {
  9252. return $working[0];
  9253. }
  9254. if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
  9255. {
  9256. if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
  9257. {
  9258. return $working;
  9259. }
  9260. if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
  9261. {
  9262. return $working;
  9263. }
  9264. if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
  9265. {
  9266. return $working;
  9267. }
  9268. if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
  9269. {
  9270. return $working;
  9271. }
  9272. }
  9273. return null;
  9274. }
  9275. public function is_feed($file)
  9276. {
  9277. if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
  9278. {
  9279. $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
  9280. $sniffed = $sniffer->get_type();
  9281. if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
  9282. {
  9283. return true;
  9284. }
  9285. else
  9286. {
  9287. return false;
  9288. }
  9289. }
  9290. elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
  9291. {
  9292. return true;
  9293. }
  9294. else
  9295. {
  9296. return false;
  9297. }
  9298. }
  9299. public function get_base()
  9300. {
  9301. if ($this->dom === null)
  9302. {
  9303. throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
  9304. }
  9305. $this->http_base = $this->file->url;
  9306. $this->base = $this->http_base;
  9307. $elements = $this->dom->getElementsByTagName('base');
  9308. foreach ($elements as $element)
  9309. {
  9310. if ($element->hasAttribute('href'))
  9311. {
  9312. $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
  9313. if ($base === false)
  9314. {
  9315. continue;
  9316. }
  9317. $this->base = $base;
  9318. $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
  9319. break;
  9320. }
  9321. }
  9322. }
  9323. public function autodiscovery()
  9324. {
  9325. $done = array();
  9326. $feeds = array();
  9327. $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
  9328. $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
  9329. $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
  9330. if (!empty($feeds))
  9331. {
  9332. return array_values($feeds);
  9333. }
  9334. else
  9335. {
  9336. return null;
  9337. }
  9338. }
  9339. protected function search_elements_by_tag($name, &$done, $feeds)
  9340. {
  9341. if ($this->dom === null)
  9342. {
  9343. throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
  9344. }
  9345. $links = $this->dom->getElementsByTagName($name);
  9346. foreach ($links as $link)
  9347. {
  9348. if ($this->checked_feeds === $this->max_checked_feeds)
  9349. {
  9350. break;
  9351. }
  9352. if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
  9353. {
  9354. $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
  9355. $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
  9356. if ($this->base_location < $line)
  9357. {
  9358. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
  9359. }
  9360. else
  9361. {
  9362. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
  9363. }
  9364. if ($href === false)
  9365. {
  9366. continue;
  9367. }
  9368. 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]))
  9369. {
  9370. $this->checked_feeds++;
  9371. $headers = array(
  9372. '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',
  9373. );
  9374. $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
  9375. 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))
  9376. {
  9377. $feeds[$href] = $feed;
  9378. }
  9379. }
  9380. $done[] = $href;
  9381. }
  9382. }
  9383. return $feeds;
  9384. }
  9385. public function get_links()
  9386. {
  9387. if ($this->dom === null)
  9388. {
  9389. throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
  9390. }
  9391. $links = $this->dom->getElementsByTagName('a');
  9392. foreach ($links as $link)
  9393. {
  9394. if ($link->hasAttribute('href'))
  9395. {
  9396. $href = trim($link->getAttribute('href'));
  9397. $parsed = $this->registry->call('Misc', 'parse_url', array($href));
  9398. if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
  9399. {
  9400. if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo())
  9401. {
  9402. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
  9403. }
  9404. else
  9405. {
  9406. $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
  9407. }
  9408. if ($href === false)
  9409. {
  9410. continue;
  9411. }
  9412. $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
  9413. if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
  9414. {
  9415. $this->local[] = $href;
  9416. }
  9417. else
  9418. {
  9419. $this->elsewhere[] = $href;
  9420. }
  9421. }
  9422. }
  9423. }
  9424. $this->local = array_unique($this->local);
  9425. $this->elsewhere = array_unique($this->elsewhere);
  9426. if (!empty($this->local) || !empty($this->elsewhere))
  9427. {
  9428. return true;
  9429. }
  9430. return null;
  9431. }
  9432. public function extension(&$array)
  9433. {
  9434. foreach ($array as $key => $value)
  9435. {
  9436. if ($this->checked_feeds === $this->max_checked_feeds)
  9437. {
  9438. break;
  9439. }
  9440. if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
  9441. {
  9442. $this->checked_feeds++;
  9443. $headers = array(
  9444. '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',
  9445. );
  9446. $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
  9447. 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))
  9448. {
  9449. return $feed;
  9450. }
  9451. else
  9452. {
  9453. unset($array[$key]);
  9454. }
  9455. }
  9456. }
  9457. return null;
  9458. }
  9459. public function body(&$array)
  9460. {
  9461. foreach ($array as $key => $value)
  9462. {
  9463. if ($this->checked_feeds === $this->max_checked_feeds)
  9464. {
  9465. break;
  9466. }
  9467. if (preg_match('/(rss|rdf|atom|xml)/i', $value))
  9468. {
  9469. $this->checked_feeds++;
  9470. $headers = array(
  9471. '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',
  9472. );
  9473. $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
  9474. 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))
  9475. {
  9476. return $feed;
  9477. }
  9478. else
  9479. {
  9480. unset($array[$key]);
  9481. }
  9482. }
  9483. }
  9484. return null;
  9485. }
  9486. }
  9487. /**
  9488. * Manages all item-related data
  9489. *
  9490. * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
  9491. *
  9492. * This class can be overloaded with {@see SimplePie::set_item_class()}
  9493. *
  9494. * @package SimplePie
  9495. * @subpackage API
  9496. */
  9497. class SimplePie_Item
  9498. {
  9499. /**
  9500. * Parent feed
  9501. *
  9502. * @access private
  9503. * @var SimplePie
  9504. */
  9505. var $feed;
  9506. /**
  9507. * Raw data
  9508. *
  9509. * @access private
  9510. * @var array
  9511. */
  9512. var $data = array();
  9513. /**
  9514. * Registry object
  9515. *
  9516. * @see set_registry
  9517. * @var SimplePie_Registry
  9518. */
  9519. protected $registry;
  9520. /**
  9521. * Create a new item object
  9522. *
  9523. * This is usually used by {@see SimplePie::get_items} and
  9524. * {@see SimplePie::get_item}. Avoid creating this manually.
  9525. *
  9526. * @param SimplePie $feed Parent feed
  9527. * @param array $data Raw data
  9528. */
  9529. public function __construct($feed, $data)
  9530. {
  9531. $this->feed = $feed;
  9532. $this->data = $data;
  9533. }
  9534. /**
  9535. * Set the registry handler
  9536. *
  9537. * This is usually used by {@see SimplePie_Registry::create}
  9538. *
  9539. * @since 1.3
  9540. * @param SimplePie_Registry $registry
  9541. */
  9542. public function set_registry(SimplePie_Registry $registry)
  9543. {
  9544. $this->registry = $registry;
  9545. }
  9546. /**
  9547. * Get a string representation of the item
  9548. *
  9549. * @return string
  9550. */
  9551. public function __toString()
  9552. {
  9553. return md5(serialize($this->data));
  9554. }
  9555. /**
  9556. * Remove items that link back to this before destroying this object
  9557. */
  9558. public function __destruct()
  9559. {
  9560. if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
  9561. {
  9562. unset($this->feed);
  9563. }
  9564. }
  9565. /**
  9566. * Get data for an item-level element
  9567. *
  9568. * This method allows you to get access to ANY element/attribute that is a
  9569. * sub-element of the item/entry tag.
  9570. *
  9571. * See {@see SimplePie::get_feed_tags()} for a description of the return value
  9572. *
  9573. * @since 1.0
  9574. * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
  9575. * @param string $namespace The URL of the XML namespace of the elements you're trying to access
  9576. * @param string $tag Tag name
  9577. * @return array
  9578. */
  9579. public function get_item_tags($namespace, $tag)
  9580. {
  9581. if (isset($this->data['child'][$namespace][$tag]))
  9582. {
  9583. return $this->data['child'][$namespace][$tag];
  9584. }
  9585. else
  9586. {
  9587. return null;
  9588. }
  9589. }
  9590. /**
  9591. * Get the base URL value from the parent feed
  9592. *
  9593. * Uses `<xml:base>`
  9594. *
  9595. * @param array $element
  9596. * @return string
  9597. */
  9598. public function get_base($element = array())
  9599. {
  9600. return $this->feed->get_base($element);
  9601. }
  9602. /**
  9603. * Sanitize feed data
  9604. *
  9605. * @access private
  9606. * @see SimplePie::sanitize()
  9607. * @param string $data Data to sanitize
  9608. * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
  9609. * @param string $base Base URL to resolve URLs against
  9610. * @return string Sanitized data
  9611. */
  9612. public function sanitize($data, $type, $base = '')
  9613. {
  9614. return $this->feed->sanitize($data, $type, $base);
  9615. }
  9616. /**
  9617. * Get the parent feed
  9618. *
  9619. * Note: this may not work as you think for multifeeds!
  9620. *
  9621. * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
  9622. * @since 1.0
  9623. * @return SimplePie
  9624. */
  9625. public function get_feed()
  9626. {
  9627. return $this->feed;
  9628. }
  9629. /**
  9630. * Get the unique identifier for the item
  9631. *
  9632. * This is usually used when writing code to check for new items in a feed.
  9633. *
  9634. * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
  9635. * for RDF. If none of these are supplied (or `$hash` is true), creates an
  9636. * MD5 hash based on the permalink and title. If either of those are not
  9637. * supplied, creates a hash based on the full feed data.
  9638. *
  9639. * @since Beta 2
  9640. * @param boolean $hash Should we force using a hash instead of the supplied ID?
  9641. * @return string
  9642. */
  9643. public function get_id($hash = false)
  9644. {
  9645. if (!$hash)
  9646. {
  9647. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
  9648. {
  9649. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9650. }
  9651. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
  9652. {
  9653. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9654. }
  9655. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  9656. {
  9657. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9658. }
  9659. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
  9660. {
  9661. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9662. }
  9663. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
  9664. {
  9665. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9666. }
  9667. elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
  9668. {
  9669. return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
  9670. }
  9671. elseif (($return = $this->get_permalink()) !== null)
  9672. {
  9673. return $return;
  9674. }
  9675. elseif (($return = $this->get_title()) !== null)
  9676. {
  9677. return $return;
  9678. }
  9679. }
  9680. if ($this->get_permalink() !== null || $this->get_title() !== null)
  9681. {
  9682. return md5($this->get_permalink() . $this->get_title());
  9683. }
  9684. else
  9685. {
  9686. return md5(serialize($this->data));
  9687. }
  9688. }
  9689. /**
  9690. * Get the title of the item
  9691. *
  9692. * Uses `<atom:title>`, `<title>` or `<dc:title>`
  9693. *
  9694. * @since Beta 2 (previously called `get_item_title` since 0.8)
  9695. * @return string|null
  9696. */
  9697. public function get_title()
  9698. {
  9699. if (!isset($this->data['title']))
  9700. {
  9701. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  9702. {
  9703. $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]));
  9704. }
  9705. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  9706. {
  9707. $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]));
  9708. }
  9709. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  9710. {
  9711. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9712. }
  9713. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  9714. {
  9715. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9716. }
  9717. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  9718. {
  9719. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9720. }
  9721. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  9722. {
  9723. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9724. }
  9725. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  9726. {
  9727. $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9728. }
  9729. else
  9730. {
  9731. $this->data['title'] = null;
  9732. }
  9733. }
  9734. return $this->data['title'];
  9735. }
  9736. /**
  9737. * Get the content for the item
  9738. *
  9739. * Prefers summaries over full content , but will return full content if a
  9740. * summary does not exist.
  9741. *
  9742. * To prefer full content instead, use {@see get_content}
  9743. *
  9744. * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
  9745. * `<itunes:subtitle>`
  9746. *
  9747. * @since 0.8
  9748. * @param boolean $description_only Should we avoid falling back to the content?
  9749. * @return string|null
  9750. */
  9751. public function get_description($description_only = false)
  9752. {
  9753. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
  9754. {
  9755. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9756. }
  9757. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
  9758. {
  9759. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9760. }
  9761. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  9762. {
  9763. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  9764. }
  9765. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  9766. {
  9767. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  9768. }
  9769. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  9770. {
  9771. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9772. }
  9773. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  9774. {
  9775. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9776. }
  9777. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  9778. {
  9779. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  9780. }
  9781. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  9782. {
  9783. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9784. }
  9785. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  9786. {
  9787. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
  9788. }
  9789. elseif (!$description_only)
  9790. {
  9791. return $this->get_content(true);
  9792. }
  9793. else
  9794. {
  9795. return null;
  9796. }
  9797. }
  9798. /**
  9799. * Get the content for the item
  9800. *
  9801. * Prefers full content over summaries, but will return a summary if full
  9802. * content does not exist.
  9803. *
  9804. * To prefer summaries instead, use {@see get_description}
  9805. *
  9806. * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
  9807. *
  9808. * @since 1.0
  9809. * @param boolean $content_only Should we avoid falling back to the description?
  9810. * @return string|null
  9811. */
  9812. public function get_content($content_only = false)
  9813. {
  9814. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
  9815. {
  9816. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9817. }
  9818. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
  9819. {
  9820. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  9821. }
  9822. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
  9823. {
  9824. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  9825. }
  9826. elseif (!$content_only)
  9827. {
  9828. return $this->get_description(true);
  9829. }
  9830. else
  9831. {
  9832. return null;
  9833. }
  9834. }
  9835. /**
  9836. * Get a category for the item
  9837. *
  9838. * @since Beta 3 (previously called `get_categories()` since Beta 2)
  9839. * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
  9840. * @return SimplePie_Category|null
  9841. */
  9842. public function get_category($key = 0)
  9843. {
  9844. $categories = $this->get_categories();
  9845. if (isset($categories[$key]))
  9846. {
  9847. return $categories[$key];
  9848. }
  9849. else
  9850. {
  9851. return null;
  9852. }
  9853. }
  9854. /**
  9855. * Get all categories for the item
  9856. *
  9857. * Uses `<atom:category>`, `<category>` or `<dc:subject>`
  9858. *
  9859. * @since Beta 3
  9860. * @return array|null List of {@see SimplePie_Category} objects
  9861. */
  9862. public function get_categories()
  9863. {
  9864. $categories = array();
  9865. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  9866. {
  9867. $term = null;
  9868. $scheme = null;
  9869. $label = null;
  9870. if (isset($category['attribs']['']['term']))
  9871. {
  9872. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  9873. }
  9874. if (isset($category['attribs']['']['scheme']))
  9875. {
  9876. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  9877. }
  9878. if (isset($category['attribs']['']['label']))
  9879. {
  9880. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  9881. }
  9882. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  9883. }
  9884. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  9885. {
  9886. // This is really the label, but keep this as the term also for BC.
  9887. // Label will also work on retrieving because that falls back to term.
  9888. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9889. if (isset($category['attribs']['']['domain']))
  9890. {
  9891. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  9892. }
  9893. else
  9894. {
  9895. $scheme = null;
  9896. }
  9897. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  9898. }
  9899. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  9900. {
  9901. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  9902. }
  9903. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  9904. {
  9905. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  9906. }
  9907. if (!empty($categories))
  9908. {
  9909. return array_unique($categories);
  9910. }
  9911. else
  9912. {
  9913. return null;
  9914. }
  9915. }
  9916. /**
  9917. * Get an author for the item
  9918. *
  9919. * @since Beta 2
  9920. * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
  9921. * @return SimplePie_Author|null
  9922. */
  9923. public function get_author($key = 0)
  9924. {
  9925. $authors = $this->get_authors();
  9926. if (isset($authors[$key]))
  9927. {
  9928. return $authors[$key];
  9929. }
  9930. else
  9931. {
  9932. return null;
  9933. }
  9934. }
  9935. /**
  9936. * Get a contributor for the item
  9937. *
  9938. * @since 1.1
  9939. * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
  9940. * @return SimplePie_Author|null
  9941. */
  9942. public function get_contributor($key = 0)
  9943. {
  9944. $contributors = $this->get_contributors();
  9945. if (isset($contributors[$key]))
  9946. {
  9947. return $contributors[$key];
  9948. }
  9949. else
  9950. {
  9951. return null;
  9952. }
  9953. }
  9954. /**
  9955. * Get all contributors for the item
  9956. *
  9957. * Uses `<atom:contributor>`
  9958. *
  9959. * @since 1.1
  9960. * @return array|null List of {@see SimplePie_Author} objects
  9961. */
  9962. public function get_contributors()
  9963. {
  9964. $contributors = array();
  9965. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  9966. {
  9967. $name = null;
  9968. $uri = null;
  9969. $email = null;
  9970. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  9971. {
  9972. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9973. }
  9974. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  9975. {
  9976. $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]));
  9977. }
  9978. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  9979. {
  9980. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9981. }
  9982. if ($name !== null || $email !== null || $uri !== null)
  9983. {
  9984. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  9985. }
  9986. }
  9987. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  9988. {
  9989. $name = null;
  9990. $url = null;
  9991. $email = null;
  9992. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  9993. {
  9994. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  9995. }
  9996. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  9997. {
  9998. $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]));
  9999. }
  10000. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  10001. {
  10002. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10003. }
  10004. if ($name !== null || $email !== null || $url !== null)
  10005. {
  10006. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  10007. }
  10008. }
  10009. if (!empty($contributors))
  10010. {
  10011. return array_unique($contributors);
  10012. }
  10013. else
  10014. {
  10015. return null;
  10016. }
  10017. }
  10018. /**
  10019. * Get all authors for the item
  10020. *
  10021. * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
  10022. *
  10023. * @since Beta 2
  10024. * @return array|null List of {@see SimplePie_Author} objects
  10025. */
  10026. public function get_authors()
  10027. {
  10028. $authors = array();
  10029. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  10030. {
  10031. $name = null;
  10032. $uri = null;
  10033. $email = null;
  10034. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  10035. {
  10036. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10037. }
  10038. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  10039. {
  10040. $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]));
  10041. }
  10042. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  10043. {
  10044. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10045. }
  10046. if ($name !== null || $email !== null || $uri !== null)
  10047. {
  10048. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  10049. }
  10050. }
  10051. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  10052. {
  10053. $name = null;
  10054. $url = null;
  10055. $email = null;
  10056. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  10057. {
  10058. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10059. }
  10060. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  10061. {
  10062. $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]));
  10063. }
  10064. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  10065. {
  10066. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10067. }
  10068. if ($name !== null || $email !== null || $url !== null)
  10069. {
  10070. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  10071. }
  10072. }
  10073. if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
  10074. {
  10075. $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
  10076. }
  10077. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  10078. {
  10079. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  10080. }
  10081. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  10082. {
  10083. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  10084. }
  10085. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  10086. {
  10087. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  10088. }
  10089. if (!empty($authors))
  10090. {
  10091. return array_unique($authors);
  10092. }
  10093. elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
  10094. {
  10095. return $authors;
  10096. }
  10097. elseif ($authors = $this->feed->get_authors())
  10098. {
  10099. return $authors;
  10100. }
  10101. else
  10102. {
  10103. return null;
  10104. }
  10105. }
  10106. /**
  10107. * Get the copyright info for the item
  10108. *
  10109. * Uses `<atom:rights>` or `<dc:rights>`
  10110. *
  10111. * @since 1.1
  10112. * @return string
  10113. */
  10114. public function get_copyright()
  10115. {
  10116. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  10117. {
  10118. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  10119. }
  10120. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  10121. {
  10122. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10123. }
  10124. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  10125. {
  10126. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10127. }
  10128. else
  10129. {
  10130. return null;
  10131. }
  10132. }
  10133. /**
  10134. * Get the posting date/time for the item
  10135. *
  10136. * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
  10137. * `<atom:modified>`, `<pubDate>` or `<dc:date>`
  10138. *
  10139. * Note: obeys PHP's timezone setting. To get a UTC date/time, use
  10140. * {@see get_gmdate}
  10141. *
  10142. * @since Beta 2 (previously called `get_item_date` since 0.8)
  10143. *
  10144. * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
  10145. * @return int|string|null
  10146. */
  10147. public function get_date($date_format = 'j F Y, g:i a')
  10148. {
  10149. if (!isset($this->data['date']))
  10150. {
  10151. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
  10152. {
  10153. $this->data['date']['raw'] = $return[0]['data'];
  10154. }
  10155. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
  10156. {
  10157. $this->data['date']['raw'] = $return[0]['data'];
  10158. }
  10159. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
  10160. {
  10161. $this->data['date']['raw'] = $return[0]['data'];
  10162. }
  10163. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
  10164. {
  10165. $this->data['date']['raw'] = $return[0]['data'];
  10166. }
  10167. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
  10168. {
  10169. $this->data['date']['raw'] = $return[0]['data'];
  10170. }
  10171. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
  10172. {
  10173. $this->data['date']['raw'] = $return[0]['data'];
  10174. }
  10175. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
  10176. {
  10177. $this->data['date']['raw'] = $return[0]['data'];
  10178. }
  10179. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
  10180. {
  10181. $this->data['date']['raw'] = $return[0]['data'];
  10182. }
  10183. if (!empty($this->data['date']['raw']))
  10184. {
  10185. $parser = $this->registry->call('Parse_Date', 'get');
  10186. $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
  10187. }
  10188. else
  10189. {
  10190. $this->data['date'] = null;
  10191. }
  10192. }
  10193. if ($this->data['date'])
  10194. {
  10195. $date_format = (string) $date_format;
  10196. switch ($date_format)
  10197. {
  10198. case '':
  10199. return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
  10200. case 'U':
  10201. return $this->data['date']['parsed'];
  10202. default:
  10203. return date($date_format, $this->data['date']['parsed']);
  10204. }
  10205. }
  10206. else
  10207. {
  10208. return null;
  10209. }
  10210. }
  10211. /**
  10212. * Get the update date/time for the item
  10213. *
  10214. * Uses `<atom:updated>`
  10215. *
  10216. * Note: obeys PHP's timezone setting. To get a UTC date/time, use
  10217. * {@see get_gmdate}
  10218. *
  10219. * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
  10220. * @return int|string|null
  10221. */
  10222. public function get_updated_date($date_format = 'j F Y, g:i a')
  10223. {
  10224. if (!isset($this->data['updated']))
  10225. {
  10226. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
  10227. {
  10228. $this->data['updated']['raw'] = $return[0]['data'];
  10229. }
  10230. if (!empty($this->data['updated']['raw']))
  10231. {
  10232. $parser = $this->registry->call('Parse_Date', 'get');
  10233. $this->data['updated']['parsed'] = $parser->parse($this->data['updated']['raw']);
  10234. }
  10235. else
  10236. {
  10237. $this->data['updated'] = null;
  10238. }
  10239. }
  10240. if ($this->data['updated'])
  10241. {
  10242. $date_format = (string) $date_format;
  10243. switch ($date_format)
  10244. {
  10245. case '':
  10246. return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
  10247. case 'U':
  10248. return $this->data['updated']['parsed'];
  10249. default:
  10250. return date($date_format, $this->data['updated']['parsed']);
  10251. }
  10252. }
  10253. else
  10254. {
  10255. return null;
  10256. }
  10257. }
  10258. /**
  10259. * Get the localized posting date/time for the item
  10260. *
  10261. * Returns the date formatted in the localized language. To display in
  10262. * languages other than the server's default, you need to change the locale
  10263. * with {@link http://php.net/setlocale setlocale()}. The available
  10264. * localizations depend on which ones are installed on your web server.
  10265. *
  10266. * @since 1.0
  10267. *
  10268. * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
  10269. * @return int|string|null
  10270. */
  10271. public function get_local_date($date_format = '%c')
  10272. {
  10273. if (!$date_format)
  10274. {
  10275. return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
  10276. }
  10277. elseif (($date = $this->get_date('U')) !== null && $date !== false)
  10278. {
  10279. return strftime($date_format, $date);
  10280. }
  10281. else
  10282. {
  10283. return null;
  10284. }
  10285. }
  10286. /**
  10287. * Get the posting date/time for the item (UTC time)
  10288. *
  10289. * @see get_date
  10290. * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
  10291. * @return int|string|null
  10292. */
  10293. public function get_gmdate($date_format = 'j F Y, g:i a')
  10294. {
  10295. $date = $this->get_date('U');
  10296. if ($date === null)
  10297. {
  10298. return null;
  10299. }
  10300. return gmdate($date_format, $date);
  10301. }
  10302. /**
  10303. * Get the update date/time for the item (UTC time)
  10304. *
  10305. * @see get_updated_date
  10306. * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
  10307. * @return int|string|null
  10308. */
  10309. public function get_updated_gmdate($date_format = 'j F Y, g:i a')
  10310. {
  10311. $date = $this->get_updated_date('U');
  10312. if ($date === null)
  10313. {
  10314. return null;
  10315. }
  10316. return gmdate($date_format, $date);
  10317. }
  10318. /**
  10319. * Get the permalink for the item
  10320. *
  10321. * Returns the first link available with a relationship of "alternate".
  10322. * Identical to {@see get_link()} with key 0
  10323. *
  10324. * @see get_link
  10325. * @since 0.8
  10326. * @return string|null Permalink URL
  10327. */
  10328. public function get_permalink()
  10329. {
  10330. $link = $this->get_link();
  10331. $enclosure = $this->get_enclosure(0);
  10332. if ($link !== null)
  10333. {
  10334. return $link;
  10335. }
  10336. elseif ($enclosure !== null)
  10337. {
  10338. return $enclosure->get_link();
  10339. }
  10340. else
  10341. {
  10342. return null;
  10343. }
  10344. }
  10345. /**
  10346. * Get a single link for the item
  10347. *
  10348. * @since Beta 3
  10349. * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
  10350. * @param string $rel The relationship of the link to return
  10351. * @return string|null Link URL
  10352. */
  10353. public function get_link($key = 0, $rel = 'alternate')
  10354. {
  10355. $links = $this->get_links($rel);
  10356. if ($links[$key] !== null)
  10357. {
  10358. return $links[$key];
  10359. }
  10360. else
  10361. {
  10362. return null;
  10363. }
  10364. }
  10365. /**
  10366. * Get all links for the item
  10367. *
  10368. * Uses `<atom:link>`, `<link>` or `<guid>`
  10369. *
  10370. * @since Beta 2
  10371. * @param string $rel The relationship of links to return
  10372. * @return array|null Links found for the item (strings)
  10373. */
  10374. public function get_links($rel = 'alternate')
  10375. {
  10376. if (!isset($this->data['links']))
  10377. {
  10378. $this->data['links'] = array();
  10379. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  10380. {
  10381. if (isset($link['attribs']['']['href']))
  10382. {
  10383. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  10384. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  10385. }
  10386. }
  10387. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  10388. {
  10389. if (isset($link['attribs']['']['href']))
  10390. {
  10391. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  10392. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  10393. }
  10394. }
  10395. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  10396. {
  10397. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10398. }
  10399. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  10400. {
  10401. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10402. }
  10403. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  10404. {
  10405. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10406. }
  10407. if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
  10408. {
  10409. if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
  10410. {
  10411. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  10412. }
  10413. }
  10414. $keys = array_keys($this->data['links']);
  10415. foreach ($keys as $key)
  10416. {
  10417. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  10418. {
  10419. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  10420. {
  10421. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  10422. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  10423. }
  10424. else
  10425. {
  10426. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  10427. }
  10428. }
  10429. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  10430. {
  10431. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  10432. }
  10433. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  10434. }
  10435. }
  10436. if (isset($this->data['links'][$rel]))
  10437. {
  10438. return $this->data['links'][$rel];
  10439. }
  10440. else
  10441. {
  10442. return null;
  10443. }
  10444. }
  10445. /**
  10446. * Get an enclosure from the item
  10447. *
  10448. * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
  10449. *
  10450. * @since Beta 2
  10451. * @todo Add ability to prefer one type of content over another (in a media group).
  10452. * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
  10453. * @return SimplePie_Enclosure|null
  10454. */
  10455. public function get_enclosure($key = 0, $prefer = null)
  10456. {
  10457. $enclosures = $this->get_enclosures();
  10458. if (isset($enclosures[$key]))
  10459. {
  10460. return $enclosures[$key];
  10461. }
  10462. else
  10463. {
  10464. return null;
  10465. }
  10466. }
  10467. /**
  10468. * Get all available enclosures (podcasts, etc.)
  10469. *
  10470. * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
  10471. *
  10472. * At this point, we're pretty much assuming that all enclosures for an item
  10473. * are the same content. Anything else is too complicated to
  10474. * properly support.
  10475. *
  10476. * @since Beta 2
  10477. * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
  10478. * @todo If an element exists at a level, but its value is empty, we should fall back to the value from the parent (if it exists).
  10479. * @return array|null List of SimplePie_Enclosure items
  10480. */
  10481. public function get_enclosures()
  10482. {
  10483. if (!isset($this->data['enclosures']))
  10484. {
  10485. $this->data['enclosures'] = array();
  10486. // Elements
  10487. $captions_parent = null;
  10488. $categories_parent = null;
  10489. $copyrights_parent = null;
  10490. $credits_parent = null;
  10491. $description_parent = null;
  10492. $duration_parent = null;
  10493. $hashes_parent = null;
  10494. $keywords_parent = null;
  10495. $player_parent = null;
  10496. $ratings_parent = null;
  10497. $restrictions_parent = null;
  10498. $thumbnails_parent = null;
  10499. $title_parent = null;
  10500. // Let's do the channel and item-level ones first, and just re-use them if we need to.
  10501. $parent = $this->get_feed();
  10502. // CAPTIONS
  10503. if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
  10504. {
  10505. foreach ($captions as $caption)
  10506. {
  10507. $caption_type = null;
  10508. $caption_lang = null;
  10509. $caption_startTime = null;
  10510. $caption_endTime = null;
  10511. $caption_text = null;
  10512. if (isset($caption['attribs']['']['type']))
  10513. {
  10514. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10515. }
  10516. if (isset($caption['attribs']['']['lang']))
  10517. {
  10518. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  10519. }
  10520. if (isset($caption['attribs']['']['start']))
  10521. {
  10522. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  10523. }
  10524. if (isset($caption['attribs']['']['end']))
  10525. {
  10526. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  10527. }
  10528. if (isset($caption['data']))
  10529. {
  10530. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10531. }
  10532. $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  10533. }
  10534. }
  10535. elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
  10536. {
  10537. foreach ($captions as $caption)
  10538. {
  10539. $caption_type = null;
  10540. $caption_lang = null;
  10541. $caption_startTime = null;
  10542. $caption_endTime = null;
  10543. $caption_text = null;
  10544. if (isset($caption['attribs']['']['type']))
  10545. {
  10546. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10547. }
  10548. if (isset($caption['attribs']['']['lang']))
  10549. {
  10550. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  10551. }
  10552. if (isset($caption['attribs']['']['start']))
  10553. {
  10554. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  10555. }
  10556. if (isset($caption['attribs']['']['end']))
  10557. {
  10558. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  10559. }
  10560. if (isset($caption['data']))
  10561. {
  10562. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10563. }
  10564. $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  10565. }
  10566. }
  10567. if (is_array($captions_parent))
  10568. {
  10569. $captions_parent = array_values(array_unique($captions_parent));
  10570. }
  10571. // CATEGORIES
  10572. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
  10573. {
  10574. $term = null;
  10575. $scheme = null;
  10576. $label = null;
  10577. if (isset($category['data']))
  10578. {
  10579. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10580. }
  10581. if (isset($category['attribs']['']['scheme']))
  10582. {
  10583. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10584. }
  10585. else
  10586. {
  10587. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  10588. }
  10589. if (isset($category['attribs']['']['label']))
  10590. {
  10591. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  10592. }
  10593. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10594. }
  10595. foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
  10596. {
  10597. $term = null;
  10598. $scheme = null;
  10599. $label = null;
  10600. if (isset($category['data']))
  10601. {
  10602. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10603. }
  10604. if (isset($category['attribs']['']['scheme']))
  10605. {
  10606. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10607. }
  10608. else
  10609. {
  10610. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  10611. }
  10612. if (isset($category['attribs']['']['label']))
  10613. {
  10614. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  10615. }
  10616. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10617. }
  10618. foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
  10619. {
  10620. $term = null;
  10621. $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
  10622. $label = null;
  10623. if (isset($category['attribs']['']['text']))
  10624. {
  10625. $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
  10626. }
  10627. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10628. if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
  10629. {
  10630. foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
  10631. {
  10632. if (isset($subcategory['attribs']['']['text']))
  10633. {
  10634. $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
  10635. }
  10636. $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
  10637. }
  10638. }
  10639. }
  10640. if (is_array($categories_parent))
  10641. {
  10642. $categories_parent = array_values(array_unique($categories_parent));
  10643. }
  10644. // COPYRIGHT
  10645. if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
  10646. {
  10647. $copyright_url = null;
  10648. $copyright_label = null;
  10649. if (isset($copyright[0]['attribs']['']['url']))
  10650. {
  10651. $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  10652. }
  10653. if (isset($copyright[0]['data']))
  10654. {
  10655. $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10656. }
  10657. $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  10658. }
  10659. elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
  10660. {
  10661. $copyright_url = null;
  10662. $copyright_label = null;
  10663. if (isset($copyright[0]['attribs']['']['url']))
  10664. {
  10665. $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  10666. }
  10667. if (isset($copyright[0]['data']))
  10668. {
  10669. $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10670. }
  10671. $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  10672. }
  10673. // CREDITS
  10674. if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
  10675. {
  10676. foreach ($credits as $credit)
  10677. {
  10678. $credit_role = null;
  10679. $credit_scheme = null;
  10680. $credit_name = null;
  10681. if (isset($credit['attribs']['']['role']))
  10682. {
  10683. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  10684. }
  10685. if (isset($credit['attribs']['']['scheme']))
  10686. {
  10687. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10688. }
  10689. else
  10690. {
  10691. $credit_scheme = 'urn:ebu';
  10692. }
  10693. if (isset($credit['data']))
  10694. {
  10695. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10696. }
  10697. $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  10698. }
  10699. }
  10700. elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
  10701. {
  10702. foreach ($credits as $credit)
  10703. {
  10704. $credit_role = null;
  10705. $credit_scheme = null;
  10706. $credit_name = null;
  10707. if (isset($credit['attribs']['']['role']))
  10708. {
  10709. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  10710. }
  10711. if (isset($credit['attribs']['']['scheme']))
  10712. {
  10713. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10714. }
  10715. else
  10716. {
  10717. $credit_scheme = 'urn:ebu';
  10718. }
  10719. if (isset($credit['data']))
  10720. {
  10721. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10722. }
  10723. $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  10724. }
  10725. }
  10726. if (is_array($credits_parent))
  10727. {
  10728. $credits_parent = array_values(array_unique($credits_parent));
  10729. }
  10730. // DESCRIPTION
  10731. if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
  10732. {
  10733. if (isset($description_parent[0]['data']))
  10734. {
  10735. $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10736. }
  10737. }
  10738. elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
  10739. {
  10740. if (isset($description_parent[0]['data']))
  10741. {
  10742. $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10743. }
  10744. }
  10745. // DURATION
  10746. if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
  10747. {
  10748. $seconds = null;
  10749. $minutes = null;
  10750. $hours = null;
  10751. if (isset($duration_parent[0]['data']))
  10752. {
  10753. $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10754. if (sizeof($temp) > 0)
  10755. {
  10756. $seconds = (int) array_pop($temp);
  10757. }
  10758. if (sizeof($temp) > 0)
  10759. {
  10760. $minutes = (int) array_pop($temp);
  10761. $seconds += $minutes * 60;
  10762. }
  10763. if (sizeof($temp) > 0)
  10764. {
  10765. $hours = (int) array_pop($temp);
  10766. $seconds += $hours * 3600;
  10767. }
  10768. unset($temp);
  10769. $duration_parent = $seconds;
  10770. }
  10771. }
  10772. // HASHES
  10773. if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
  10774. {
  10775. foreach ($hashes_iterator as $hash)
  10776. {
  10777. $value = null;
  10778. $algo = null;
  10779. if (isset($hash['data']))
  10780. {
  10781. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10782. }
  10783. if (isset($hash['attribs']['']['algo']))
  10784. {
  10785. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  10786. }
  10787. else
  10788. {
  10789. $algo = 'md5';
  10790. }
  10791. $hashes_parent[] = $algo.':'.$value;
  10792. }
  10793. }
  10794. elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
  10795. {
  10796. foreach ($hashes_iterator as $hash)
  10797. {
  10798. $value = null;
  10799. $algo = null;
  10800. if (isset($hash['data']))
  10801. {
  10802. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10803. }
  10804. if (isset($hash['attribs']['']['algo']))
  10805. {
  10806. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  10807. }
  10808. else
  10809. {
  10810. $algo = 'md5';
  10811. }
  10812. $hashes_parent[] = $algo.':'.$value;
  10813. }
  10814. }
  10815. if (is_array($hashes_parent))
  10816. {
  10817. $hashes_parent = array_values(array_unique($hashes_parent));
  10818. }
  10819. // KEYWORDS
  10820. if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
  10821. {
  10822. if (isset($keywords[0]['data']))
  10823. {
  10824. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10825. foreach ($temp as $word)
  10826. {
  10827. $keywords_parent[] = trim($word);
  10828. }
  10829. }
  10830. unset($temp);
  10831. }
  10832. elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
  10833. {
  10834. if (isset($keywords[0]['data']))
  10835. {
  10836. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10837. foreach ($temp as $word)
  10838. {
  10839. $keywords_parent[] = trim($word);
  10840. }
  10841. }
  10842. unset($temp);
  10843. }
  10844. elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
  10845. {
  10846. if (isset($keywords[0]['data']))
  10847. {
  10848. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10849. foreach ($temp as $word)
  10850. {
  10851. $keywords_parent[] = trim($word);
  10852. }
  10853. }
  10854. unset($temp);
  10855. }
  10856. elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
  10857. {
  10858. if (isset($keywords[0]['data']))
  10859. {
  10860. $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  10861. foreach ($temp as $word)
  10862. {
  10863. $keywords_parent[] = trim($word);
  10864. }
  10865. }
  10866. unset($temp);
  10867. }
  10868. if (is_array($keywords_parent))
  10869. {
  10870. $keywords_parent = array_values(array_unique($keywords_parent));
  10871. }
  10872. // PLAYER
  10873. if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
  10874. {
  10875. if (isset($player_parent[0]['attribs']['']['url']))
  10876. {
  10877. $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10878. }
  10879. }
  10880. elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
  10881. {
  10882. if (isset($player_parent[0]['attribs']['']['url']))
  10883. {
  10884. $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  10885. }
  10886. }
  10887. // RATINGS
  10888. if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
  10889. {
  10890. foreach ($ratings as $rating)
  10891. {
  10892. $rating_scheme = null;
  10893. $rating_value = null;
  10894. if (isset($rating['attribs']['']['scheme']))
  10895. {
  10896. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10897. }
  10898. else
  10899. {
  10900. $rating_scheme = 'urn:simple';
  10901. }
  10902. if (isset($rating['data']))
  10903. {
  10904. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10905. }
  10906. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10907. }
  10908. }
  10909. elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
  10910. {
  10911. foreach ($ratings as $rating)
  10912. {
  10913. $rating_scheme = 'urn:itunes';
  10914. $rating_value = null;
  10915. if (isset($rating['data']))
  10916. {
  10917. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10918. }
  10919. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10920. }
  10921. }
  10922. elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
  10923. {
  10924. foreach ($ratings as $rating)
  10925. {
  10926. $rating_scheme = null;
  10927. $rating_value = null;
  10928. if (isset($rating['attribs']['']['scheme']))
  10929. {
  10930. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  10931. }
  10932. else
  10933. {
  10934. $rating_scheme = 'urn:simple';
  10935. }
  10936. if (isset($rating['data']))
  10937. {
  10938. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10939. }
  10940. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10941. }
  10942. }
  10943. elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
  10944. {
  10945. foreach ($ratings as $rating)
  10946. {
  10947. $rating_scheme = 'urn:itunes';
  10948. $rating_value = null;
  10949. if (isset($rating['data']))
  10950. {
  10951. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10952. }
  10953. $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  10954. }
  10955. }
  10956. if (is_array($ratings_parent))
  10957. {
  10958. $ratings_parent = array_values(array_unique($ratings_parent));
  10959. }
  10960. // RESTRICTIONS
  10961. if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
  10962. {
  10963. foreach ($restrictions as $restriction)
  10964. {
  10965. $restriction_relationship = null;
  10966. $restriction_type = null;
  10967. $restriction_value = null;
  10968. if (isset($restriction['attribs']['']['relationship']))
  10969. {
  10970. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  10971. }
  10972. if (isset($restriction['attribs']['']['type']))
  10973. {
  10974. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  10975. }
  10976. if (isset($restriction['data']))
  10977. {
  10978. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  10979. }
  10980. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10981. }
  10982. }
  10983. elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
  10984. {
  10985. foreach ($restrictions as $restriction)
  10986. {
  10987. $restriction_relationship = 'allow';
  10988. $restriction_type = null;
  10989. $restriction_value = 'itunes';
  10990. if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
  10991. {
  10992. $restriction_relationship = 'deny';
  10993. }
  10994. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  10995. }
  10996. }
  10997. elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
  10998. {
  10999. foreach ($restrictions as $restriction)
  11000. {
  11001. $restriction_relationship = null;
  11002. $restriction_type = null;
  11003. $restriction_value = null;
  11004. if (isset($restriction['attribs']['']['relationship']))
  11005. {
  11006. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  11007. }
  11008. if (isset($restriction['attribs']['']['type']))
  11009. {
  11010. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11011. }
  11012. if (isset($restriction['data']))
  11013. {
  11014. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11015. }
  11016. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  11017. }
  11018. }
  11019. elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
  11020. {
  11021. foreach ($restrictions as $restriction)
  11022. {
  11023. $restriction_relationship = 'allow';
  11024. $restriction_type = null;
  11025. $restriction_value = 'itunes';
  11026. if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
  11027. {
  11028. $restriction_relationship = 'deny';
  11029. }
  11030. $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  11031. }
  11032. }
  11033. if (is_array($restrictions_parent))
  11034. {
  11035. $restrictions_parent = array_values(array_unique($restrictions_parent));
  11036. }
  11037. else
  11038. {
  11039. $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
  11040. }
  11041. // THUMBNAILS
  11042. if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
  11043. {
  11044. foreach ($thumbnails as $thumbnail)
  11045. {
  11046. if (isset($thumbnail['attribs']['']['url']))
  11047. {
  11048. $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11049. }
  11050. }
  11051. }
  11052. elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
  11053. {
  11054. foreach ($thumbnails as $thumbnail)
  11055. {
  11056. if (isset($thumbnail['attribs']['']['url']))
  11057. {
  11058. $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11059. }
  11060. }
  11061. }
  11062. // TITLES
  11063. if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
  11064. {
  11065. if (isset($title_parent[0]['data']))
  11066. {
  11067. $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11068. }
  11069. }
  11070. elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
  11071. {
  11072. if (isset($title_parent[0]['data']))
  11073. {
  11074. $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11075. }
  11076. }
  11077. // Clear the memory
  11078. unset($parent);
  11079. // Attributes
  11080. $bitrate = null;
  11081. $channels = null;
  11082. $duration = null;
  11083. $expression = null;
  11084. $framerate = null;
  11085. $height = null;
  11086. $javascript = null;
  11087. $lang = null;
  11088. $length = null;
  11089. $medium = null;
  11090. $samplingrate = null;
  11091. $type = null;
  11092. $url = null;
  11093. $width = null;
  11094. // Elements
  11095. $captions = null;
  11096. $categories = null;
  11097. $copyrights = null;
  11098. $credits = null;
  11099. $description = null;
  11100. $hashes = null;
  11101. $keywords = null;
  11102. $player = null;
  11103. $ratings = null;
  11104. $restrictions = null;
  11105. $thumbnails = null;
  11106. $title = null;
  11107. // If we have media:group tags, loop through them.
  11108. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
  11109. {
  11110. if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
  11111. {
  11112. // If we have media:content tags, loop through them.
  11113. foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
  11114. {
  11115. if (isset($content['attribs']['']['url']))
  11116. {
  11117. // Attributes
  11118. $bitrate = null;
  11119. $channels = null;
  11120. $duration = null;
  11121. $expression = null;
  11122. $framerate = null;
  11123. $height = null;
  11124. $javascript = null;
  11125. $lang = null;
  11126. $length = null;
  11127. $medium = null;
  11128. $samplingrate = null;
  11129. $type = null;
  11130. $url = null;
  11131. $width = null;
  11132. // Elements
  11133. $captions = null;
  11134. $categories = null;
  11135. $copyrights = null;
  11136. $credits = null;
  11137. $description = null;
  11138. $hashes = null;
  11139. $keywords = null;
  11140. $player = null;
  11141. $ratings = null;
  11142. $restrictions = null;
  11143. $thumbnails = null;
  11144. $title = null;
  11145. // Start checking the attributes of media:content
  11146. if (isset($content['attribs']['']['bitrate']))
  11147. {
  11148. $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11149. }
  11150. if (isset($content['attribs']['']['channels']))
  11151. {
  11152. $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
  11153. }
  11154. if (isset($content['attribs']['']['duration']))
  11155. {
  11156. $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
  11157. }
  11158. else
  11159. {
  11160. $duration = $duration_parent;
  11161. }
  11162. if (isset($content['attribs']['']['expression']))
  11163. {
  11164. $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
  11165. }
  11166. if (isset($content['attribs']['']['framerate']))
  11167. {
  11168. $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11169. }
  11170. if (isset($content['attribs']['']['height']))
  11171. {
  11172. $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
  11173. }
  11174. if (isset($content['attribs']['']['lang']))
  11175. {
  11176. $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11177. }
  11178. if (isset($content['attribs']['']['fileSize']))
  11179. {
  11180. $length = ceil($content['attribs']['']['fileSize']);
  11181. }
  11182. if (isset($content['attribs']['']['medium']))
  11183. {
  11184. $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
  11185. }
  11186. if (isset($content['attribs']['']['samplingrate']))
  11187. {
  11188. $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11189. }
  11190. if (isset($content['attribs']['']['type']))
  11191. {
  11192. $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11193. }
  11194. if (isset($content['attribs']['']['width']))
  11195. {
  11196. $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
  11197. }
  11198. $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11199. // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
  11200. // CAPTIONS
  11201. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  11202. {
  11203. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  11204. {
  11205. $caption_type = null;
  11206. $caption_lang = null;
  11207. $caption_startTime = null;
  11208. $caption_endTime = null;
  11209. $caption_text = null;
  11210. if (isset($caption['attribs']['']['type']))
  11211. {
  11212. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11213. }
  11214. if (isset($caption['attribs']['']['lang']))
  11215. {
  11216. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11217. }
  11218. if (isset($caption['attribs']['']['start']))
  11219. {
  11220. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  11221. }
  11222. if (isset($caption['attribs']['']['end']))
  11223. {
  11224. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  11225. }
  11226. if (isset($caption['data']))
  11227. {
  11228. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11229. }
  11230. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  11231. }
  11232. if (is_array($captions))
  11233. {
  11234. $captions = array_values(array_unique($captions));
  11235. }
  11236. }
  11237. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  11238. {
  11239. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  11240. {
  11241. $caption_type = null;
  11242. $caption_lang = null;
  11243. $caption_startTime = null;
  11244. $caption_endTime = null;
  11245. $caption_text = null;
  11246. if (isset($caption['attribs']['']['type']))
  11247. {
  11248. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11249. }
  11250. if (isset($caption['attribs']['']['lang']))
  11251. {
  11252. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11253. }
  11254. if (isset($caption['attribs']['']['start']))
  11255. {
  11256. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  11257. }
  11258. if (isset($caption['attribs']['']['end']))
  11259. {
  11260. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  11261. }
  11262. if (isset($caption['data']))
  11263. {
  11264. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11265. }
  11266. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  11267. }
  11268. if (is_array($captions))
  11269. {
  11270. $captions = array_values(array_unique($captions));
  11271. }
  11272. }
  11273. else
  11274. {
  11275. $captions = $captions_parent;
  11276. }
  11277. // CATEGORIES
  11278. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  11279. {
  11280. foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  11281. {
  11282. $term = null;
  11283. $scheme = null;
  11284. $label = null;
  11285. if (isset($category['data']))
  11286. {
  11287. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11288. }
  11289. if (isset($category['attribs']['']['scheme']))
  11290. {
  11291. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11292. }
  11293. else
  11294. {
  11295. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  11296. }
  11297. if (isset($category['attribs']['']['label']))
  11298. {
  11299. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  11300. }
  11301. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  11302. }
  11303. }
  11304. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  11305. {
  11306. foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  11307. {
  11308. $term = null;
  11309. $scheme = null;
  11310. $label = null;
  11311. if (isset($category['data']))
  11312. {
  11313. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11314. }
  11315. if (isset($category['attribs']['']['scheme']))
  11316. {
  11317. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11318. }
  11319. else
  11320. {
  11321. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  11322. }
  11323. if (isset($category['attribs']['']['label']))
  11324. {
  11325. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  11326. }
  11327. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  11328. }
  11329. }
  11330. if (is_array($categories) && is_array($categories_parent))
  11331. {
  11332. $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
  11333. }
  11334. elseif (is_array($categories))
  11335. {
  11336. $categories = array_values(array_unique($categories));
  11337. }
  11338. elseif (is_array($categories_parent))
  11339. {
  11340. $categories = array_values(array_unique($categories_parent));
  11341. }
  11342. // COPYRIGHTS
  11343. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  11344. {
  11345. $copyright_url = null;
  11346. $copyright_label = null;
  11347. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  11348. {
  11349. $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  11350. }
  11351. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  11352. {
  11353. $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11354. }
  11355. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  11356. }
  11357. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  11358. {
  11359. $copyright_url = null;
  11360. $copyright_label = null;
  11361. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  11362. {
  11363. $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  11364. }
  11365. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  11366. {
  11367. $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11368. }
  11369. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  11370. }
  11371. else
  11372. {
  11373. $copyrights = $copyrights_parent;
  11374. }
  11375. // CREDITS
  11376. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  11377. {
  11378. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  11379. {
  11380. $credit_role = null;
  11381. $credit_scheme = null;
  11382. $credit_name = null;
  11383. if (isset($credit['attribs']['']['role']))
  11384. {
  11385. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  11386. }
  11387. if (isset($credit['attribs']['']['scheme']))
  11388. {
  11389. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11390. }
  11391. else
  11392. {
  11393. $credit_scheme = 'urn:ebu';
  11394. }
  11395. if (isset($credit['data']))
  11396. {
  11397. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11398. }
  11399. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  11400. }
  11401. if (is_array($credits))
  11402. {
  11403. $credits = array_values(array_unique($credits));
  11404. }
  11405. }
  11406. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  11407. {
  11408. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  11409. {
  11410. $credit_role = null;
  11411. $credit_scheme = null;
  11412. $credit_name = null;
  11413. if (isset($credit['attribs']['']['role']))
  11414. {
  11415. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  11416. }
  11417. if (isset($credit['attribs']['']['scheme']))
  11418. {
  11419. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11420. }
  11421. else
  11422. {
  11423. $credit_scheme = 'urn:ebu';
  11424. }
  11425. if (isset($credit['data']))
  11426. {
  11427. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11428. }
  11429. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  11430. }
  11431. if (is_array($credits))
  11432. {
  11433. $credits = array_values(array_unique($credits));
  11434. }
  11435. }
  11436. else
  11437. {
  11438. $credits = $credits_parent;
  11439. }
  11440. // DESCRIPTION
  11441. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  11442. {
  11443. $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11444. }
  11445. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  11446. {
  11447. $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11448. }
  11449. else
  11450. {
  11451. $description = $description_parent;
  11452. }
  11453. // HASHES
  11454. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  11455. {
  11456. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  11457. {
  11458. $value = null;
  11459. $algo = null;
  11460. if (isset($hash['data']))
  11461. {
  11462. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11463. }
  11464. if (isset($hash['attribs']['']['algo']))
  11465. {
  11466. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  11467. }
  11468. else
  11469. {
  11470. $algo = 'md5';
  11471. }
  11472. $hashes[] = $algo.':'.$value;
  11473. }
  11474. if (is_array($hashes))
  11475. {
  11476. $hashes = array_values(array_unique($hashes));
  11477. }
  11478. }
  11479. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  11480. {
  11481. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  11482. {
  11483. $value = null;
  11484. $algo = null;
  11485. if (isset($hash['data']))
  11486. {
  11487. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11488. }
  11489. if (isset($hash['attribs']['']['algo']))
  11490. {
  11491. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  11492. }
  11493. else
  11494. {
  11495. $algo = 'md5';
  11496. }
  11497. $hashes[] = $algo.':'.$value;
  11498. }
  11499. if (is_array($hashes))
  11500. {
  11501. $hashes = array_values(array_unique($hashes));
  11502. }
  11503. }
  11504. else
  11505. {
  11506. $hashes = $hashes_parent;
  11507. }
  11508. // KEYWORDS
  11509. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  11510. {
  11511. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  11512. {
  11513. $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  11514. foreach ($temp as $word)
  11515. {
  11516. $keywords[] = trim($word);
  11517. }
  11518. unset($temp);
  11519. }
  11520. if (is_array($keywords))
  11521. {
  11522. $keywords = array_values(array_unique($keywords));
  11523. }
  11524. }
  11525. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  11526. {
  11527. if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  11528. {
  11529. $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  11530. foreach ($temp as $word)
  11531. {
  11532. $keywords[] = trim($word);
  11533. }
  11534. unset($temp);
  11535. }
  11536. if (is_array($keywords))
  11537. {
  11538. $keywords = array_values(array_unique($keywords));
  11539. }
  11540. }
  11541. else
  11542. {
  11543. $keywords = $keywords_parent;
  11544. }
  11545. // PLAYER
  11546. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  11547. {
  11548. $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11549. }
  11550. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  11551. {
  11552. $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11553. }
  11554. else
  11555. {
  11556. $player = $player_parent;
  11557. }
  11558. // RATINGS
  11559. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  11560. {
  11561. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  11562. {
  11563. $rating_scheme = null;
  11564. $rating_value = null;
  11565. if (isset($rating['attribs']['']['scheme']))
  11566. {
  11567. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11568. }
  11569. else
  11570. {
  11571. $rating_scheme = 'urn:simple';
  11572. }
  11573. if (isset($rating['data']))
  11574. {
  11575. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11576. }
  11577. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  11578. }
  11579. if (is_array($ratings))
  11580. {
  11581. $ratings = array_values(array_unique($ratings));
  11582. }
  11583. }
  11584. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  11585. {
  11586. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  11587. {
  11588. $rating_scheme = null;
  11589. $rating_value = null;
  11590. if (isset($rating['attribs']['']['scheme']))
  11591. {
  11592. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11593. }
  11594. else
  11595. {
  11596. $rating_scheme = 'urn:simple';
  11597. }
  11598. if (isset($rating['data']))
  11599. {
  11600. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11601. }
  11602. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  11603. }
  11604. if (is_array($ratings))
  11605. {
  11606. $ratings = array_values(array_unique($ratings));
  11607. }
  11608. }
  11609. else
  11610. {
  11611. $ratings = $ratings_parent;
  11612. }
  11613. // RESTRICTIONS
  11614. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  11615. {
  11616. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  11617. {
  11618. $restriction_relationship = null;
  11619. $restriction_type = null;
  11620. $restriction_value = null;
  11621. if (isset($restriction['attribs']['']['relationship']))
  11622. {
  11623. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  11624. }
  11625. if (isset($restriction['attribs']['']['type']))
  11626. {
  11627. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11628. }
  11629. if (isset($restriction['data']))
  11630. {
  11631. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11632. }
  11633. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  11634. }
  11635. if (is_array($restrictions))
  11636. {
  11637. $restrictions = array_values(array_unique($restrictions));
  11638. }
  11639. }
  11640. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  11641. {
  11642. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  11643. {
  11644. $restriction_relationship = null;
  11645. $restriction_type = null;
  11646. $restriction_value = null;
  11647. if (isset($restriction['attribs']['']['relationship']))
  11648. {
  11649. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  11650. }
  11651. if (isset($restriction['attribs']['']['type']))
  11652. {
  11653. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11654. }
  11655. if (isset($restriction['data']))
  11656. {
  11657. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11658. }
  11659. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  11660. }
  11661. if (is_array($restrictions))
  11662. {
  11663. $restrictions = array_values(array_unique($restrictions));
  11664. }
  11665. }
  11666. else
  11667. {
  11668. $restrictions = $restrictions_parent;
  11669. }
  11670. // THUMBNAILS
  11671. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  11672. {
  11673. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  11674. {
  11675. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11676. }
  11677. if (is_array($thumbnails))
  11678. {
  11679. $thumbnails = array_values(array_unique($thumbnails));
  11680. }
  11681. }
  11682. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  11683. {
  11684. foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  11685. {
  11686. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11687. }
  11688. if (is_array($thumbnails))
  11689. {
  11690. $thumbnails = array_values(array_unique($thumbnails));
  11691. }
  11692. }
  11693. else
  11694. {
  11695. $thumbnails = $thumbnails_parent;
  11696. }
  11697. // TITLES
  11698. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  11699. {
  11700. $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11701. }
  11702. elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  11703. {
  11704. $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11705. }
  11706. else
  11707. {
  11708. $title = $title_parent;
  11709. }
  11710. $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));
  11711. }
  11712. }
  11713. }
  11714. }
  11715. // If we have standalone media:content tags, loop through them.
  11716. if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
  11717. {
  11718. foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
  11719. {
  11720. if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  11721. {
  11722. // Attributes
  11723. $bitrate = null;
  11724. $channels = null;
  11725. $duration = null;
  11726. $expression = null;
  11727. $framerate = null;
  11728. $height = null;
  11729. $javascript = null;
  11730. $lang = null;
  11731. $length = null;
  11732. $medium = null;
  11733. $samplingrate = null;
  11734. $type = null;
  11735. $url = null;
  11736. $width = null;
  11737. // Elements
  11738. $captions = null;
  11739. $categories = null;
  11740. $copyrights = null;
  11741. $credits = null;
  11742. $description = null;
  11743. $hashes = null;
  11744. $keywords = null;
  11745. $player = null;
  11746. $ratings = null;
  11747. $restrictions = null;
  11748. $thumbnails = null;
  11749. $title = null;
  11750. // Start checking the attributes of media:content
  11751. if (isset($content['attribs']['']['bitrate']))
  11752. {
  11753. $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11754. }
  11755. if (isset($content['attribs']['']['channels']))
  11756. {
  11757. $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
  11758. }
  11759. if (isset($content['attribs']['']['duration']))
  11760. {
  11761. $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
  11762. }
  11763. else
  11764. {
  11765. $duration = $duration_parent;
  11766. }
  11767. if (isset($content['attribs']['']['expression']))
  11768. {
  11769. $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
  11770. }
  11771. if (isset($content['attribs']['']['framerate']))
  11772. {
  11773. $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11774. }
  11775. if (isset($content['attribs']['']['height']))
  11776. {
  11777. $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
  11778. }
  11779. if (isset($content['attribs']['']['lang']))
  11780. {
  11781. $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11782. }
  11783. if (isset($content['attribs']['']['fileSize']))
  11784. {
  11785. $length = ceil($content['attribs']['']['fileSize']);
  11786. }
  11787. if (isset($content['attribs']['']['medium']))
  11788. {
  11789. $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
  11790. }
  11791. if (isset($content['attribs']['']['samplingrate']))
  11792. {
  11793. $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
  11794. }
  11795. if (isset($content['attribs']['']['type']))
  11796. {
  11797. $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11798. }
  11799. if (isset($content['attribs']['']['width']))
  11800. {
  11801. $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
  11802. }
  11803. if (isset($content['attribs']['']['url']))
  11804. {
  11805. $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  11806. }
  11807. // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
  11808. // CAPTIONS
  11809. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
  11810. {
  11811. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
  11812. {
  11813. $caption_type = null;
  11814. $caption_lang = null;
  11815. $caption_startTime = null;
  11816. $caption_endTime = null;
  11817. $caption_text = null;
  11818. if (isset($caption['attribs']['']['type']))
  11819. {
  11820. $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  11821. }
  11822. if (isset($caption['attribs']['']['lang']))
  11823. {
  11824. $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  11825. }
  11826. if (isset($caption['attribs']['']['start']))
  11827. {
  11828. $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
  11829. }
  11830. if (isset($caption['attribs']['']['end']))
  11831. {
  11832. $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
  11833. }
  11834. if (isset($caption['data']))
  11835. {
  11836. $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11837. }
  11838. $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
  11839. }
  11840. if (is_array($captions))
  11841. {
  11842. $captions = array_values(array_unique($captions));
  11843. }
  11844. }
  11845. else
  11846. {
  11847. $captions = $captions_parent;
  11848. }
  11849. // CATEGORIES
  11850. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
  11851. {
  11852. foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
  11853. {
  11854. $term = null;
  11855. $scheme = null;
  11856. $label = null;
  11857. if (isset($category['data']))
  11858. {
  11859. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11860. }
  11861. if (isset($category['attribs']['']['scheme']))
  11862. {
  11863. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11864. }
  11865. else
  11866. {
  11867. $scheme = 'http://search.yahoo.com/mrss/category_schema';
  11868. }
  11869. if (isset($category['attribs']['']['label']))
  11870. {
  11871. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  11872. }
  11873. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  11874. }
  11875. }
  11876. if (is_array($categories) && is_array($categories_parent))
  11877. {
  11878. $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
  11879. }
  11880. elseif (is_array($categories))
  11881. {
  11882. $categories = array_values(array_unique($categories));
  11883. }
  11884. elseif (is_array($categories_parent))
  11885. {
  11886. $categories = array_values(array_unique($categories_parent));
  11887. }
  11888. else
  11889. {
  11890. $categories = null;
  11891. }
  11892. // COPYRIGHTS
  11893. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
  11894. {
  11895. $copyright_url = null;
  11896. $copyright_label = null;
  11897. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
  11898. {
  11899. $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
  11900. }
  11901. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
  11902. {
  11903. $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11904. }
  11905. $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
  11906. }
  11907. else
  11908. {
  11909. $copyrights = $copyrights_parent;
  11910. }
  11911. // CREDITS
  11912. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
  11913. {
  11914. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
  11915. {
  11916. $credit_role = null;
  11917. $credit_scheme = null;
  11918. $credit_name = null;
  11919. if (isset($credit['attribs']['']['role']))
  11920. {
  11921. $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
  11922. }
  11923. if (isset($credit['attribs']['']['scheme']))
  11924. {
  11925. $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  11926. }
  11927. else
  11928. {
  11929. $credit_scheme = 'urn:ebu';
  11930. }
  11931. if (isset($credit['data']))
  11932. {
  11933. $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11934. }
  11935. $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
  11936. }
  11937. if (is_array($credits))
  11938. {
  11939. $credits = array_values(array_unique($credits));
  11940. }
  11941. }
  11942. else
  11943. {
  11944. $credits = $credits_parent;
  11945. }
  11946. // DESCRIPTION
  11947. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
  11948. {
  11949. $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11950. }
  11951. else
  11952. {
  11953. $description = $description_parent;
  11954. }
  11955. // HASHES
  11956. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
  11957. {
  11958. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
  11959. {
  11960. $value = null;
  11961. $algo = null;
  11962. if (isset($hash['data']))
  11963. {
  11964. $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  11965. }
  11966. if (isset($hash['attribs']['']['algo']))
  11967. {
  11968. $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
  11969. }
  11970. else
  11971. {
  11972. $algo = 'md5';
  11973. }
  11974. $hashes[] = $algo.':'.$value;
  11975. }
  11976. if (is_array($hashes))
  11977. {
  11978. $hashes = array_values(array_unique($hashes));
  11979. }
  11980. }
  11981. else
  11982. {
  11983. $hashes = $hashes_parent;
  11984. }
  11985. // KEYWORDS
  11986. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
  11987. {
  11988. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
  11989. {
  11990. $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
  11991. foreach ($temp as $word)
  11992. {
  11993. $keywords[] = trim($word);
  11994. }
  11995. unset($temp);
  11996. }
  11997. if (is_array($keywords))
  11998. {
  11999. $keywords = array_values(array_unique($keywords));
  12000. }
  12001. }
  12002. else
  12003. {
  12004. $keywords = $keywords_parent;
  12005. }
  12006. // PLAYER
  12007. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
  12008. {
  12009. $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  12010. }
  12011. else
  12012. {
  12013. $player = $player_parent;
  12014. }
  12015. // RATINGS
  12016. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
  12017. {
  12018. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
  12019. {
  12020. $rating_scheme = null;
  12021. $rating_value = null;
  12022. if (isset($rating['attribs']['']['scheme']))
  12023. {
  12024. $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  12025. }
  12026. else
  12027. {
  12028. $rating_scheme = 'urn:simple';
  12029. }
  12030. if (isset($rating['data']))
  12031. {
  12032. $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  12033. }
  12034. $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
  12035. }
  12036. if (is_array($ratings))
  12037. {
  12038. $ratings = array_values(array_unique($ratings));
  12039. }
  12040. }
  12041. else
  12042. {
  12043. $ratings = $ratings_parent;
  12044. }
  12045. // RESTRICTIONS
  12046. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
  12047. {
  12048. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
  12049. {
  12050. $restriction_relationship = null;
  12051. $restriction_type = null;
  12052. $restriction_value = null;
  12053. if (isset($restriction['attribs']['']['relationship']))
  12054. {
  12055. $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
  12056. }
  12057. if (isset($restriction['attribs']['']['type']))
  12058. {
  12059. $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  12060. }
  12061. if (isset($restriction['data']))
  12062. {
  12063. $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  12064. }
  12065. $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
  12066. }
  12067. if (is_array($restrictions))
  12068. {
  12069. $restrictions = array_values(array_unique($restrictions));
  12070. }
  12071. }
  12072. else
  12073. {
  12074. $restrictions = $restrictions_parent;
  12075. }
  12076. // THUMBNAILS
  12077. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
  12078. {
  12079. foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
  12080. {
  12081. $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
  12082. }
  12083. if (is_array($thumbnails))
  12084. {
  12085. $thumbnails = array_values(array_unique($thumbnails));
  12086. }
  12087. }
  12088. else
  12089. {
  12090. $thumbnails = $thumbnails_parent;
  12091. }
  12092. // TITLES
  12093. if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
  12094. {
  12095. $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  12096. }
  12097. else
  12098. {
  12099. $title = $title_parent;
  12100. }
  12101. $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));
  12102. }
  12103. }
  12104. }
  12105. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
  12106. {
  12107. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  12108. {
  12109. // Attributes
  12110. $bitrate = null;
  12111. $channels = null;
  12112. $duration = null;
  12113. $expression = null;
  12114. $framerate = null;
  12115. $height = null;
  12116. $javascript = null;
  12117. $lang = null;
  12118. $length = null;
  12119. $medium = null;
  12120. $samplingrate = null;
  12121. $type = null;
  12122. $url = null;
  12123. $width = null;
  12124. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  12125. if (isset($link['attribs']['']['type']))
  12126. {
  12127. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  12128. }
  12129. if (isset($link['attribs']['']['length']))
  12130. {
  12131. $length = ceil($link['attribs']['']['length']);
  12132. }
  12133. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  12134. $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));
  12135. }
  12136. }
  12137. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
  12138. {
  12139. if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
  12140. {
  12141. // Attributes
  12142. $bitrate = null;
  12143. $channels = null;
  12144. $duration = null;
  12145. $expression = null;
  12146. $framerate = null;
  12147. $height = null;
  12148. $javascript = null;
  12149. $lang = null;
  12150. $length = null;
  12151. $medium = null;
  12152. $samplingrate = null;
  12153. $type = null;
  12154. $url = null;
  12155. $width = null;
  12156. $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  12157. if (isset($link['attribs']['']['type']))
  12158. {
  12159. $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  12160. }
  12161. if (isset($link['attribs']['']['length']))
  12162. {
  12163. $length = ceil($link['attribs']['']['length']);
  12164. }
  12165. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  12166. $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));
  12167. }
  12168. }
  12169. if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
  12170. {
  12171. if (isset($enclosure[0]['attribs']['']['url']))
  12172. {
  12173. // Attributes
  12174. $bitrate = null;
  12175. $channels = null;
  12176. $duration = null;
  12177. $expression = null;
  12178. $framerate = null;
  12179. $height = null;
  12180. $javascript = null;
  12181. $lang = null;
  12182. $length = null;
  12183. $medium = null;
  12184. $samplingrate = null;
  12185. $type = null;
  12186. $url = null;
  12187. $width = null;
  12188. $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
  12189. if (isset($enclosure[0]['attribs']['']['type']))
  12190. {
  12191. $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
  12192. }
  12193. if (isset($enclosure[0]['attribs']['']['length']))
  12194. {
  12195. $length = ceil($enclosure[0]['attribs']['']['length']);
  12196. }
  12197. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  12198. $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));
  12199. }
  12200. }
  12201. 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))
  12202. {
  12203. // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
  12204. $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));
  12205. }
  12206. $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
  12207. }
  12208. if (!empty($this->data['enclosures']))
  12209. {
  12210. return $this->data['enclosures'];
  12211. }
  12212. else
  12213. {
  12214. return null;
  12215. }
  12216. }
  12217. /**
  12218. * Get the latitude coordinates for the item
  12219. *
  12220. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  12221. *
  12222. * Uses `<geo:lat>` or `<georss:point>`
  12223. *
  12224. * @since 1.0
  12225. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  12226. * @link http://www.georss.org/ GeoRSS
  12227. * @return string|null
  12228. */
  12229. public function get_latitude()
  12230. {
  12231. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  12232. {
  12233. return (float) $return[0]['data'];
  12234. }
  12235. 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))
  12236. {
  12237. return (float) $match[1];
  12238. }
  12239. else
  12240. {
  12241. return null;
  12242. }
  12243. }
  12244. /**
  12245. * Get the longitude coordinates for the item
  12246. *
  12247. * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
  12248. *
  12249. * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
  12250. *
  12251. * @since 1.0
  12252. * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
  12253. * @link http://www.georss.org/ GeoRSS
  12254. * @return string|null
  12255. */
  12256. public function get_longitude()
  12257. {
  12258. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  12259. {
  12260. return (float) $return[0]['data'];
  12261. }
  12262. elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  12263. {
  12264. return (float) $return[0]['data'];
  12265. }
  12266. 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))
  12267. {
  12268. return (float) $match[2];
  12269. }
  12270. else
  12271. {
  12272. return null;
  12273. }
  12274. }
  12275. /**
  12276. * Get the `<atom:source>` for the item
  12277. *
  12278. * @since 1.1
  12279. * @return SimplePie_Source|null
  12280. */
  12281. public function get_source()
  12282. {
  12283. if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
  12284. {
  12285. return $this->registry->create('Source', array($this, $return[0]));
  12286. }
  12287. else
  12288. {
  12289. return null;
  12290. }
  12291. }
  12292. }
  12293. /**
  12294. * Decode 'gzip' encoded HTTP data
  12295. *
  12296. * @package SimplePie
  12297. * @subpackage HTTP
  12298. * @link http://www.gzip.org/format.txt
  12299. */
  12300. class SimplePie_gzdecode
  12301. {
  12302. /**
  12303. * Compressed data
  12304. *
  12305. * @access private
  12306. * @var string
  12307. * @see gzdecode::$data
  12308. */
  12309. var $compressed_data;
  12310. /**
  12311. * Size of compressed data
  12312. *
  12313. * @access private
  12314. * @var int
  12315. */
  12316. var $compressed_size;
  12317. /**
  12318. * Minimum size of a valid gzip string
  12319. *
  12320. * @access private
  12321. * @var int
  12322. */
  12323. var $min_compressed_size = 18;
  12324. /**
  12325. * Current position of pointer
  12326. *
  12327. * @access private
  12328. * @var int
  12329. */
  12330. var $position = 0;
  12331. /**
  12332. * Flags (FLG)
  12333. *
  12334. * @access private
  12335. * @var int
  12336. */
  12337. var $flags;
  12338. /**
  12339. * Uncompressed data
  12340. *
  12341. * @access public
  12342. * @see gzdecode::$compressed_data
  12343. * @var string
  12344. */
  12345. var $data;
  12346. /**
  12347. * Modified time
  12348. *
  12349. * @access public
  12350. * @var int
  12351. */
  12352. var $MTIME;
  12353. /**
  12354. * Extra Flags
  12355. *
  12356. * @access public
  12357. * @var int
  12358. */
  12359. var $XFL;
  12360. /**
  12361. * Operating System
  12362. *
  12363. * @access public
  12364. * @var int
  12365. */
  12366. var $OS;
  12367. /**
  12368. * Subfield ID 1
  12369. *
  12370. * @access public
  12371. * @see gzdecode::$extra_field
  12372. * @see gzdecode::$SI2
  12373. * @var string
  12374. */
  12375. var $SI1;
  12376. /**
  12377. * Subfield ID 2
  12378. *
  12379. * @access public
  12380. * @see gzdecode::$extra_field
  12381. * @see gzdecode::$SI1
  12382. * @var string
  12383. */
  12384. var $SI2;
  12385. /**
  12386. * Extra field content
  12387. *
  12388. * @access public
  12389. * @see gzdecode::$SI1
  12390. * @see gzdecode::$SI2
  12391. * @var string
  12392. */
  12393. var $extra_field;
  12394. /**
  12395. * Original filename
  12396. *
  12397. * @access public
  12398. * @var string
  12399. */
  12400. var $filename;
  12401. /**
  12402. * Human readable comment
  12403. *
  12404. * @access public
  12405. * @var string
  12406. */
  12407. var $comment;
  12408. /**
  12409. * Don't allow anything to be set
  12410. *
  12411. * @param string $name
  12412. * @param mixed $value
  12413. */
  12414. public function __set($name, $value)
  12415. {
  12416. trigger_error("Cannot write property $name", E_USER_ERROR);
  12417. }
  12418. /**
  12419. * Set the compressed string and related properties
  12420. *
  12421. * @param string $data
  12422. */
  12423. public function __construct($data)
  12424. {
  12425. $this->compressed_data = $data;
  12426. $this->compressed_size = strlen($data);
  12427. }
  12428. /**
  12429. * Decode the GZIP stream
  12430. *
  12431. * @return bool Successfulness
  12432. */
  12433. public function parse()
  12434. {
  12435. if ($this->compressed_size >= $this->min_compressed_size)
  12436. {
  12437. // Check ID1, ID2, and CM
  12438. if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
  12439. {
  12440. return false;
  12441. }
  12442. // Get the FLG (FLaGs)
  12443. $this->flags = ord($this->compressed_data[3]);
  12444. // FLG bits above (1 << 4) are reserved
  12445. if ($this->flags > 0x1F)
  12446. {
  12447. return false;
  12448. }
  12449. // Advance the pointer after the above
  12450. $this->position += 4;
  12451. // MTIME
  12452. $mtime = substr($this->compressed_data, $this->position, 4);
  12453. // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
  12454. if (current(unpack('S', "\x00\x01")) === 1)
  12455. {
  12456. $mtime = strrev($mtime);
  12457. }
  12458. $this->MTIME = current(unpack('l', $mtime));
  12459. $this->position += 4;
  12460. // Get the XFL (eXtra FLags)
  12461. $this->XFL = ord($this->compressed_data[$this->position++]);
  12462. // Get the OS (Operating System)
  12463. $this->OS = ord($this->compressed_data[$this->position++]);
  12464. // Parse the FEXTRA
  12465. if ($this->flags & 4)
  12466. {
  12467. // Read subfield IDs
  12468. $this->SI1 = $this->compressed_data[$this->position++];
  12469. $this->SI2 = $this->compressed_data[$this->position++];
  12470. // SI2 set to zero is reserved for future use
  12471. if ($this->SI2 === "\x00")
  12472. {
  12473. return false;
  12474. }
  12475. // Get the length of the extra field
  12476. $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  12477. $this->position += 2;
  12478. // Check the length of the string is still valid
  12479. $this->min_compressed_size += $len + 4;
  12480. if ($this->compressed_size >= $this->min_compressed_size)
  12481. {
  12482. // Set the extra field to the given data
  12483. $this->extra_field = substr($this->compressed_data, $this->position, $len);
  12484. $this->position += $len;
  12485. }
  12486. else
  12487. {
  12488. return false;
  12489. }
  12490. }
  12491. // Parse the FNAME
  12492. if ($this->flags & 8)
  12493. {
  12494. // Get the length of the filename
  12495. $len = strcspn($this->compressed_data, "\x00", $this->position);
  12496. // Check the length of the string is still valid
  12497. $this->min_compressed_size += $len + 1;
  12498. if ($this->compressed_size >= $this->min_compressed_size)
  12499. {
  12500. // Set the original filename to the given string
  12501. $this->filename = substr($this->compressed_data, $this->position, $len);
  12502. $this->position += $len + 1;
  12503. }
  12504. else
  12505. {
  12506. return false;
  12507. }
  12508. }
  12509. // Parse the FCOMMENT
  12510. if ($this->flags & 16)
  12511. {
  12512. // Get the length of the comment
  12513. $len = strcspn($this->compressed_data, "\x00", $this->position);
  12514. // Check the length of the string is still valid
  12515. $this->min_compressed_size += $len + 1;
  12516. if ($this->compressed_size >= $this->min_compressed_size)
  12517. {
  12518. // Set the original comment to the given string
  12519. $this->comment = substr($this->compressed_data, $this->position, $len);
  12520. $this->position += $len + 1;
  12521. }
  12522. else
  12523. {
  12524. return false;
  12525. }
  12526. }
  12527. // Parse the FHCRC
  12528. if ($this->flags & 2)
  12529. {
  12530. // Check the length of the string is still valid
  12531. $this->min_compressed_size += $len + 2;
  12532. if ($this->compressed_size >= $this->min_compressed_size)
  12533. {
  12534. // Read the CRC
  12535. $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  12536. // Check the CRC matches
  12537. if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
  12538. {
  12539. $this->position += 2;
  12540. }
  12541. else
  12542. {
  12543. return false;
  12544. }
  12545. }
  12546. else
  12547. {
  12548. return false;
  12549. }
  12550. }
  12551. // Decompress the actual data
  12552. if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
  12553. {
  12554. return false;
  12555. }
  12556. else
  12557. {
  12558. $this->position = $this->compressed_size - 8;
  12559. }
  12560. // Check CRC of data
  12561. $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  12562. $this->position += 4;
  12563. /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
  12564. {
  12565. return false;
  12566. }*/
  12567. // Check ISIZE of data
  12568. $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  12569. $this->position += 4;
  12570. if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
  12571. {
  12572. return false;
  12573. }
  12574. // Wow, against all odds, we've actually got a valid gzip string
  12575. return true;
  12576. }
  12577. else
  12578. {
  12579. return false;
  12580. }
  12581. }
  12582. }
  12583. /**
  12584. * HTTP Response Parser
  12585. *
  12586. * @package SimplePie
  12587. * @subpackage HTTP
  12588. */
  12589. class SimplePie_HTTP_Parser
  12590. {
  12591. /**
  12592. * HTTP Version
  12593. *
  12594. * @var float
  12595. */
  12596. public $http_version = 0.0;
  12597. /**
  12598. * Status code
  12599. *
  12600. * @var int
  12601. */
  12602. public $status_code = 0;
  12603. /**
  12604. * Reason phrase
  12605. *
  12606. * @var string
  12607. */
  12608. public $reason = '';
  12609. /**
  12610. * Key/value pairs of the headers
  12611. *
  12612. * @var array
  12613. */
  12614. public $headers = array();
  12615. /**
  12616. * Body of the response
  12617. *
  12618. * @var string
  12619. */
  12620. public $body = '';
  12621. /**
  12622. * Current state of the state machine
  12623. *
  12624. * @var string
  12625. */
  12626. protected $state = 'http_version';
  12627. /**
  12628. * Input data
  12629. *
  12630. * @var string
  12631. */
  12632. protected $data = '';
  12633. /**
  12634. * Input data length (to avoid calling strlen() everytime this is needed)
  12635. *
  12636. * @var int
  12637. */
  12638. protected $data_length = 0;
  12639. /**
  12640. * Current position of the pointer
  12641. *
  12642. * @var int
  12643. */
  12644. protected $position = 0;
  12645. /**
  12646. * Name of the hedaer currently being parsed
  12647. *
  12648. * @var string
  12649. */
  12650. protected $name = '';
  12651. /**
  12652. * Value of the hedaer currently being parsed
  12653. *
  12654. * @var string
  12655. */
  12656. protected $value = '';
  12657. /**
  12658. * Create an instance of the class with the input data
  12659. *
  12660. * @param string $data Input data
  12661. */
  12662. public function __construct($data)
  12663. {
  12664. $this->data = $data;
  12665. $this->data_length = strlen($this->data);
  12666. }
  12667. /**
  12668. * Parse the input data
  12669. *
  12670. * @return bool true on success, false on failure
  12671. */
  12672. public function parse()
  12673. {
  12674. while ($this->state && $this->state !== 'emit' && $this->has_data())
  12675. {
  12676. $state = $this->state;
  12677. $this->$state();
  12678. }
  12679. $this->data = '';
  12680. if ($this->state === 'emit' || $this->state === 'body')
  12681. {
  12682. return true;
  12683. }
  12684. else
  12685. {
  12686. $this->http_version = '';
  12687. $this->status_code = '';
  12688. $this->reason = '';
  12689. $this->headers = array();
  12690. $this->body = '';
  12691. return false;
  12692. }
  12693. }
  12694. /**
  12695. * Check whether there is data beyond the pointer
  12696. *
  12697. * @return bool true if there is further data, false if not
  12698. */
  12699. protected function has_data()
  12700. {
  12701. return (bool) ($this->position < $this->data_length);
  12702. }
  12703. /**
  12704. * See if the next character is LWS
  12705. *
  12706. * @return bool true if the next character is LWS, false if not
  12707. */
  12708. protected function is_linear_whitespace()
  12709. {
  12710. return (bool) ($this->data[$this->position] === "\x09"
  12711. || $this->data[$this->position] === "\x20"
  12712. || ($this->data[$this->position] === "\x0A"
  12713. && isset($this->data[$this->position + 1])
  12714. && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
  12715. }
  12716. /**
  12717. * Parse the HTTP version
  12718. */
  12719. protected function http_version()
  12720. {
  12721. if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
  12722. {
  12723. $len = strspn($this->data, '0123456789.', 5);
  12724. $this->http_version = substr($this->data, 5, $len);
  12725. $this->position += 5 + $len;
  12726. if (substr_count($this->http_version, '.') <= 1)
  12727. {
  12728. $this->http_version = (float) $this->http_version;
  12729. $this->position += strspn($this->data, "\x09\x20", $this->position);
  12730. $this->state = 'status';
  12731. }
  12732. else
  12733. {
  12734. $this->state = false;
  12735. }
  12736. }
  12737. else
  12738. {
  12739. $this->state = false;
  12740. }
  12741. }
  12742. /**
  12743. * Parse the status code
  12744. */
  12745. protected function status()
  12746. {
  12747. if ($len = strspn($this->data, '0123456789', $this->position))
  12748. {
  12749. $this->status_code = (int) substr($this->data, $this->position, $len);
  12750. $this->position += $len;
  12751. $this->state = 'reason';
  12752. }
  12753. else
  12754. {
  12755. $this->state = false;
  12756. }
  12757. }
  12758. /**
  12759. * Parse the reason phrase
  12760. */
  12761. protected function reason()
  12762. {
  12763. $len = strcspn($this->data, "\x0A", $this->position);
  12764. $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
  12765. $this->position += $len + 1;
  12766. $this->state = 'new_line';
  12767. }
  12768. /**
  12769. * Deal with a new line, shifting data around as needed
  12770. */
  12771. protected function new_line()
  12772. {
  12773. $this->value = trim($this->value, "\x0D\x20");
  12774. if ($this->name !== '' && $this->value !== '')
  12775. {
  12776. $this->name = strtolower($this->name);
  12777. // We should only use the last Content-Type header. c.f. issue #1
  12778. if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
  12779. {
  12780. $this->headers[$this->name] .= ', ' . $this->value;
  12781. }
  12782. else
  12783. {
  12784. $this->headers[$this->name] = $this->value;
  12785. }
  12786. }
  12787. $this->name = '';
  12788. $this->value = '';
  12789. if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
  12790. {
  12791. $this->position += 2;
  12792. $this->state = 'body';
  12793. }
  12794. elseif ($this->data[$this->position] === "\x0A")
  12795. {
  12796. $this->position++;
  12797. $this->state = 'body';
  12798. }
  12799. else
  12800. {
  12801. $this->state = 'name';
  12802. }
  12803. }
  12804. /**
  12805. * Parse a header name
  12806. */
  12807. protected function name()
  12808. {
  12809. $len = strcspn($this->data, "\x0A:", $this->position);
  12810. if (isset($this->data[$this->position + $len]))
  12811. {
  12812. if ($this->data[$this->position + $len] === "\x0A")
  12813. {
  12814. $this->position += $len;
  12815. $this->state = 'new_line';
  12816. }
  12817. else
  12818. {
  12819. $this->name = substr($this->data, $this->position, $len);
  12820. $this->position += $len + 1;
  12821. $this->state = 'value';
  12822. }
  12823. }
  12824. else
  12825. {
  12826. $this->state = false;
  12827. }
  12828. }
  12829. /**
  12830. * Parse LWS, replacing consecutive LWS characters with a single space
  12831. */
  12832. protected function linear_whitespace()
  12833. {
  12834. do
  12835. {
  12836. if (substr($this->data, $this->position, 2) === "\x0D\x0A")
  12837. {
  12838. $this->position += 2;
  12839. }
  12840. elseif ($this->data[$this->position] === "\x0A")
  12841. {
  12842. $this->position++;
  12843. }
  12844. $this->position += strspn($this->data, "\x09\x20", $this->position);
  12845. } while ($this->has_data() && $this->is_linear_whitespace());
  12846. $this->value .= "\x20";
  12847. }
  12848. /**
  12849. * See what state to move to while within non-quoted header values
  12850. */
  12851. protected function value()
  12852. {
  12853. if ($this->is_linear_whitespace())
  12854. {
  12855. $this->linear_whitespace();
  12856. }
  12857. else
  12858. {
  12859. switch ($this->data[$this->position])
  12860. {
  12861. case '"':
  12862. // Workaround for ETags: we have to include the quotes as
  12863. // part of the tag.
  12864. if (strtolower($this->name) === 'etag')
  12865. {
  12866. $this->value .= '"';
  12867. $this->position++;
  12868. $this->state = 'value_char';
  12869. break;
  12870. }
  12871. $this->position++;
  12872. $this->state = 'quote';
  12873. break;
  12874. case "\x0A":
  12875. $this->position++;
  12876. $this->state = 'new_line';
  12877. break;
  12878. default:
  12879. $this->state = 'value_char';
  12880. break;
  12881. }
  12882. }
  12883. }
  12884. /**
  12885. * Parse a header value while outside quotes
  12886. */
  12887. protected function value_char()
  12888. {
  12889. $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
  12890. $this->value .= substr($this->data, $this->position, $len);
  12891. $this->position += $len;
  12892. $this->state = 'value';
  12893. }
  12894. /**
  12895. * See what state to move to while within quoted header values
  12896. */
  12897. protected function quote()
  12898. {
  12899. if ($this->is_linear_whitespace())
  12900. {
  12901. $this->linear_whitespace();
  12902. }
  12903. else
  12904. {
  12905. switch ($this->data[$this->position])
  12906. {
  12907. case '"':
  12908. $this->position++;
  12909. $this->state = 'value';
  12910. break;
  12911. case "\x0A":
  12912. $this->position++;
  12913. $this->state = 'new_line';
  12914. break;
  12915. case '\\':
  12916. $this->position++;
  12917. $this->state = 'quote_escaped';
  12918. break;
  12919. default:
  12920. $this->state = 'quote_char';
  12921. break;
  12922. }
  12923. }
  12924. }
  12925. /**
  12926. * Parse a header value while within quotes
  12927. */
  12928. protected function quote_char()
  12929. {
  12930. $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
  12931. $this->value .= substr($this->data, $this->position, $len);
  12932. $this->position += $len;
  12933. $this->state = 'value';
  12934. }
  12935. /**
  12936. * Parse an escaped character within quotes
  12937. */
  12938. protected function quote_escaped()
  12939. {
  12940. $this->value .= $this->data[$this->position];
  12941. $this->position++;
  12942. $this->state = 'quote';
  12943. }
  12944. /**
  12945. * Parse the body
  12946. */
  12947. protected function body()
  12948. {
  12949. $this->body = substr($this->data, $this->position);
  12950. if (!empty($this->headers['transfer-encoding']))
  12951. {
  12952. unset($this->headers['transfer-encoding']);
  12953. $this->state = 'chunked';
  12954. }
  12955. else
  12956. {
  12957. $this->state = 'emit';
  12958. }
  12959. }
  12960. /**
  12961. * Parsed a "Transfer-Encoding: chunked" body
  12962. */
  12963. protected function chunked()
  12964. {
  12965. if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
  12966. {
  12967. $this->state = 'emit';
  12968. return;
  12969. }
  12970. $decoded = '';
  12971. $encoded = $this->body;
  12972. while (true)
  12973. {
  12974. $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
  12975. if (!$is_chunked)
  12976. {
  12977. // Looks like it's not chunked after all
  12978. $this->state = 'emit';
  12979. return;
  12980. }
  12981. $length = hexdec(trim($matches[1]));
  12982. if ($length === 0)
  12983. {
  12984. // Ignore trailer headers
  12985. $this->state = 'emit';
  12986. $this->body = $decoded;
  12987. return;
  12988. }
  12989. $chunk_length = strlen($matches[0]);
  12990. $decoded .= $part = substr($encoded, $chunk_length, $length);
  12991. $encoded = substr($encoded, $chunk_length + $length + 2);
  12992. if (trim($encoded) === '0' || empty($encoded))
  12993. {
  12994. $this->state = 'emit';
  12995. $this->body = $decoded;
  12996. return;
  12997. }
  12998. }
  12999. }
  13000. }
  13001. /**
  13002. * SimplePie class.
  13003. *
  13004. * Class for backward compatibility.
  13005. *
  13006. * @deprecated Use {@see SimplePie} directly
  13007. * @package SimplePie
  13008. * @subpackage API
  13009. */
  13010. class SimplePie_Core extends SimplePie
  13011. {
  13012. }
  13013. /**
  13014. * Handles `<media:restriction>` as defined in Media RSS
  13015. *
  13016. * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
  13017. *
  13018. * This class can be overloaded with {@see SimplePie::set_restriction_class()}
  13019. *
  13020. * @package SimplePie
  13021. * @subpackage API
  13022. */
  13023. class SimplePie_Restriction
  13024. {
  13025. /**
  13026. * Relationship ('allow'/'deny')
  13027. *
  13028. * @var string
  13029. * @see get_relationship()
  13030. */
  13031. var $relationship;
  13032. /**
  13033. * Type of restriction
  13034. *
  13035. * @var string
  13036. * @see get_type()
  13037. */
  13038. var $type;
  13039. /**
  13040. * Restricted values
  13041. *
  13042. * @var string
  13043. * @see get_value()
  13044. */
  13045. var $value;
  13046. /**
  13047. * Constructor, used to input the data
  13048. *
  13049. * For documentation on all the parameters, see the corresponding
  13050. * properties and their accessors
  13051. */
  13052. public function __construct($relationship = null, $type = null, $value = null)
  13053. {
  13054. $this->relationship = $relationship;
  13055. $this->type = $type;
  13056. $this->value = $value;
  13057. }
  13058. /**
  13059. * String-ified version
  13060. *
  13061. * @return string
  13062. */
  13063. public function __toString()
  13064. {
  13065. // There is no $this->data here
  13066. return md5(serialize($this));
  13067. }
  13068. /**
  13069. * Get the relationship
  13070. *
  13071. * @return string|null Either 'allow' or 'deny'
  13072. */
  13073. public function get_relationship()
  13074. {
  13075. if ($this->relationship !== null)
  13076. {
  13077. return $this->relationship;
  13078. }
  13079. else
  13080. {
  13081. return null;
  13082. }
  13083. }
  13084. /**
  13085. * Get the type
  13086. *
  13087. * @return string|null
  13088. */
  13089. public function get_type()
  13090. {
  13091. if ($this->type !== null)
  13092. {
  13093. return $this->type;
  13094. }
  13095. else
  13096. {
  13097. return null;
  13098. }
  13099. }
  13100. /**
  13101. * Get the list of restricted things
  13102. *
  13103. * @return string|null
  13104. */
  13105. public function get_value()
  13106. {
  13107. if ($this->value !== null)
  13108. {
  13109. return $this->value;
  13110. }
  13111. else
  13112. {
  13113. return null;
  13114. }
  13115. }
  13116. }
  13117. /**
  13118. * General SimplePie exception class
  13119. *
  13120. * @package SimplePie
  13121. */
  13122. class SimplePie_Exception extends Exception
  13123. {
  13124. }
  13125. /**
  13126. * Handles `<atom:source>`
  13127. *
  13128. * Used by {@see SimplePie_Item::get_source()}
  13129. *
  13130. * This class can be overloaded with {@see SimplePie::set_source_class()}
  13131. *
  13132. * @package SimplePie
  13133. * @subpackage API
  13134. */
  13135. class SimplePie_Source
  13136. {
  13137. var $item;
  13138. var $data = array();
  13139. protected $registry;
  13140. public function __construct($item, $data)
  13141. {
  13142. $this->item = $item;
  13143. $this->data = $data;
  13144. }
  13145. public function set_registry(SimplePie_Registry $registry)
  13146. {
  13147. $this->registry = $registry;
  13148. }
  13149. public function __toString()
  13150. {
  13151. return md5(serialize($this->data));
  13152. }
  13153. public function get_source_tags($namespace, $tag)
  13154. {
  13155. if (isset($this->data['child'][$namespace][$tag]))
  13156. {
  13157. return $this->data['child'][$namespace][$tag];
  13158. }
  13159. else
  13160. {
  13161. return null;
  13162. }
  13163. }
  13164. public function get_base($element = array())
  13165. {
  13166. return $this->item->get_base($element);
  13167. }
  13168. public function sanitize($data, $type, $base = '')
  13169. {
  13170. return $this->item->sanitize($data, $type, $base);
  13171. }
  13172. public function get_item()
  13173. {
  13174. return $this->item;
  13175. }
  13176. public function get_title()
  13177. {
  13178. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
  13179. {
  13180. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13181. }
  13182. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
  13183. {
  13184. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13185. }
  13186. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
  13187. {
  13188. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13189. }
  13190. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
  13191. {
  13192. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13193. }
  13194. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
  13195. {
  13196. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13197. }
  13198. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
  13199. {
  13200. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13201. }
  13202. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
  13203. {
  13204. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13205. }
  13206. else
  13207. {
  13208. return null;
  13209. }
  13210. }
  13211. public function get_category($key = 0)
  13212. {
  13213. $categories = $this->get_categories();
  13214. if (isset($categories[$key]))
  13215. {
  13216. return $categories[$key];
  13217. }
  13218. else
  13219. {
  13220. return null;
  13221. }
  13222. }
  13223. public function get_categories()
  13224. {
  13225. $categories = array();
  13226. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
  13227. {
  13228. $term = null;
  13229. $scheme = null;
  13230. $label = null;
  13231. if (isset($category['attribs']['']['term']))
  13232. {
  13233. $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
  13234. }
  13235. if (isset($category['attribs']['']['scheme']))
  13236. {
  13237. $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
  13238. }
  13239. if (isset($category['attribs']['']['label']))
  13240. {
  13241. $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
  13242. }
  13243. $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
  13244. }
  13245. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
  13246. {
  13247. // This is really the label, but keep this as the term also for BC.
  13248. // Label will also work on retrieving because that falls back to term.
  13249. $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13250. if (isset($category['attribs']['']['domain']))
  13251. {
  13252. $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
  13253. }
  13254. else
  13255. {
  13256. $scheme = null;
  13257. }
  13258. $categories[] = $this->registry->create('Category', array($term, $scheme, null));
  13259. }
  13260. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
  13261. {
  13262. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13263. }
  13264. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
  13265. {
  13266. $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13267. }
  13268. if (!empty($categories))
  13269. {
  13270. return array_unique($categories);
  13271. }
  13272. else
  13273. {
  13274. return null;
  13275. }
  13276. }
  13277. public function get_author($key = 0)
  13278. {
  13279. $authors = $this->get_authors();
  13280. if (isset($authors[$key]))
  13281. {
  13282. return $authors[$key];
  13283. }
  13284. else
  13285. {
  13286. return null;
  13287. }
  13288. }
  13289. public function get_authors()
  13290. {
  13291. $authors = array();
  13292. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
  13293. {
  13294. $name = null;
  13295. $uri = null;
  13296. $email = null;
  13297. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  13298. {
  13299. $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13300. }
  13301. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  13302. {
  13303. $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]));
  13304. }
  13305. if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  13306. {
  13307. $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13308. }
  13309. if ($name !== null || $email !== null || $uri !== null)
  13310. {
  13311. $authors[] = $this->registry->create('Author', array($name, $uri, $email));
  13312. }
  13313. }
  13314. if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
  13315. {
  13316. $name = null;
  13317. $url = null;
  13318. $email = null;
  13319. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  13320. {
  13321. $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13322. }
  13323. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  13324. {
  13325. $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]));
  13326. }
  13327. if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  13328. {
  13329. $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13330. }
  13331. if ($name !== null || $email !== null || $url !== null)
  13332. {
  13333. $authors[] = $this->registry->create('Author', array($name, $url, $email));
  13334. }
  13335. }
  13336. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
  13337. {
  13338. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13339. }
  13340. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
  13341. {
  13342. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13343. }
  13344. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
  13345. {
  13346. $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
  13347. }
  13348. if (!empty($authors))
  13349. {
  13350. return array_unique($authors);
  13351. }
  13352. else
  13353. {
  13354. return null;
  13355. }
  13356. }
  13357. public function get_contributor($key = 0)
  13358. {
  13359. $contributors = $this->get_contributors();
  13360. if (isset($contributors[$key]))
  13361. {
  13362. return $contributors[$key];
  13363. }
  13364. else
  13365. {
  13366. return null;
  13367. }
  13368. }
  13369. public function get_contributors()
  13370. {
  13371. $contributors = array();
  13372. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
  13373. {
  13374. $name = null;
  13375. $uri = null;
  13376. $email = null;
  13377. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
  13378. {
  13379. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13380. }
  13381. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
  13382. {
  13383. $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]));
  13384. }
  13385. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
  13386. {
  13387. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13388. }
  13389. if ($name !== null || $email !== null || $uri !== null)
  13390. {
  13391. $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
  13392. }
  13393. }
  13394. foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
  13395. {
  13396. $name = null;
  13397. $url = null;
  13398. $email = null;
  13399. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
  13400. {
  13401. $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13402. }
  13403. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
  13404. {
  13405. $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]));
  13406. }
  13407. if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
  13408. {
  13409. $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13410. }
  13411. if ($name !== null || $email !== null || $url !== null)
  13412. {
  13413. $contributors[] = $this->registry->create('Author', array($name, $url, $email));
  13414. }
  13415. }
  13416. if (!empty($contributors))
  13417. {
  13418. return array_unique($contributors);
  13419. }
  13420. else
  13421. {
  13422. return null;
  13423. }
  13424. }
  13425. public function get_link($key = 0, $rel = 'alternate')
  13426. {
  13427. $links = $this->get_links($rel);
  13428. if (isset($links[$key]))
  13429. {
  13430. return $links[$key];
  13431. }
  13432. else
  13433. {
  13434. return null;
  13435. }
  13436. }
  13437. /**
  13438. * Added for parity between the parent-level and the item/entry-level.
  13439. */
  13440. public function get_permalink()
  13441. {
  13442. return $this->get_link(0);
  13443. }
  13444. public function get_links($rel = 'alternate')
  13445. {
  13446. if (!isset($this->data['links']))
  13447. {
  13448. $this->data['links'] = array();
  13449. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
  13450. {
  13451. foreach ($links as $link)
  13452. {
  13453. if (isset($link['attribs']['']['href']))
  13454. {
  13455. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  13456. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  13457. }
  13458. }
  13459. }
  13460. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
  13461. {
  13462. foreach ($links as $link)
  13463. {
  13464. if (isset($link['attribs']['']['href']))
  13465. {
  13466. $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
  13467. $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
  13468. }
  13469. }
  13470. }
  13471. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
  13472. {
  13473. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  13474. }
  13475. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
  13476. {
  13477. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  13478. }
  13479. if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
  13480. {
  13481. $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
  13482. }
  13483. $keys = array_keys($this->data['links']);
  13484. foreach ($keys as $key)
  13485. {
  13486. if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
  13487. {
  13488. if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
  13489. {
  13490. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
  13491. $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
  13492. }
  13493. else
  13494. {
  13495. $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
  13496. }
  13497. }
  13498. elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
  13499. {
  13500. $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
  13501. }
  13502. $this->data['links'][$key] = array_unique($this->data['links'][$key]);
  13503. }
  13504. }
  13505. if (isset($this->data['links'][$rel]))
  13506. {
  13507. return $this->data['links'][$rel];
  13508. }
  13509. else
  13510. {
  13511. return null;
  13512. }
  13513. }
  13514. public function get_description()
  13515. {
  13516. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
  13517. {
  13518. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13519. }
  13520. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
  13521. {
  13522. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13523. }
  13524. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
  13525. {
  13526. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13527. }
  13528. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
  13529. {
  13530. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13531. }
  13532. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
  13533. {
  13534. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
  13535. }
  13536. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
  13537. {
  13538. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13539. }
  13540. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
  13541. {
  13542. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13543. }
  13544. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
  13545. {
  13546. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  13547. }
  13548. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
  13549. {
  13550. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
  13551. }
  13552. else
  13553. {
  13554. return null;
  13555. }
  13556. }
  13557. public function get_copyright()
  13558. {
  13559. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
  13560. {
  13561. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13562. }
  13563. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
  13564. {
  13565. return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
  13566. }
  13567. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
  13568. {
  13569. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13570. }
  13571. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
  13572. {
  13573. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13574. }
  13575. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
  13576. {
  13577. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13578. }
  13579. else
  13580. {
  13581. return null;
  13582. }
  13583. }
  13584. public function get_language()
  13585. {
  13586. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
  13587. {
  13588. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13589. }
  13590. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
  13591. {
  13592. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13593. }
  13594. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
  13595. {
  13596. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
  13597. }
  13598. elseif (isset($this->data['xml_lang']))
  13599. {
  13600. return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
  13601. }
  13602. else
  13603. {
  13604. return null;
  13605. }
  13606. }
  13607. public function get_latitude()
  13608. {
  13609. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
  13610. {
  13611. return (float) $return[0]['data'];
  13612. }
  13613. 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))
  13614. {
  13615. return (float) $match[1];
  13616. }
  13617. else
  13618. {
  13619. return null;
  13620. }
  13621. }
  13622. public function get_longitude()
  13623. {
  13624. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
  13625. {
  13626. return (float) $return[0]['data'];
  13627. }
  13628. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
  13629. {
  13630. return (float) $return[0]['data'];
  13631. }
  13632. 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))
  13633. {
  13634. return (float) $match[2];
  13635. }
  13636. else
  13637. {
  13638. return null;
  13639. }
  13640. }
  13641. public function get_image_url()
  13642. {
  13643. if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
  13644. {
  13645. return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
  13646. }
  13647. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
  13648. {
  13649. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  13650. }
  13651. elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
  13652. {
  13653. return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
  13654. }
  13655. else
  13656. {
  13657. return null;
  13658. }
  13659. }
  13660. }
  13661. /**
  13662. * Miscellanous utilities
  13663. *
  13664. * @package SimplePie
  13665. */
  13666. class SimplePie_Misc
  13667. {
  13668. public static function time_hms($seconds)
  13669. {
  13670. $time = '';
  13671. $hours = floor($seconds / 3600);
  13672. $remainder = $seconds % 3600;
  13673. if ($hours > 0)
  13674. {
  13675. $time .= $hours.':';
  13676. }
  13677. $minutes = floor($remainder / 60);
  13678. $seconds = $remainder % 60;
  13679. if ($minutes < 10 && $hours > 0)
  13680. {
  13681. $minutes = '0' . $minutes;
  13682. }
  13683. if ($seconds < 10)
  13684. {
  13685. $seconds = '0' . $seconds;
  13686. }
  13687. $time .= $minutes.':';
  13688. $time .= $seconds;
  13689. return $time;
  13690. }
  13691. public static function absolutize_url($relative, $base)
  13692. {
  13693. $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
  13694. if ($iri === false)
  13695. {
  13696. return false;
  13697. }
  13698. return $iri->get_uri();
  13699. }
  13700. /**
  13701. * Get a HTML/XML element from a HTML string
  13702. *
  13703. * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
  13704. * @param string $realname Element name (including namespace prefix if applicable)
  13705. * @param string $string HTML document
  13706. * @return array
  13707. */
  13708. public static function get_element($realname, $string)
  13709. {
  13710. $return = array();
  13711. $name = preg_quote($realname, '/');
  13712. if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
  13713. {
  13714. for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
  13715. {
  13716. $return[$i]['tag'] = $realname;
  13717. $return[$i]['full'] = $matches[$i][0][0];
  13718. $return[$i]['offset'] = $matches[$i][0][1];
  13719. if (strlen($matches[$i][3][0]) <= 2)
  13720. {
  13721. $return[$i]['self_closing'] = true;
  13722. }
  13723. else
  13724. {
  13725. $return[$i]['self_closing'] = false;
  13726. $return[$i]['content'] = $matches[$i][4][0];
  13727. }
  13728. $return[$i]['attribs'] = array();
  13729. 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))
  13730. {
  13731. for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
  13732. {
  13733. if (count($attribs[$j]) === 2)
  13734. {
  13735. $attribs[$j][2] = $attribs[$j][1];
  13736. }
  13737. $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
  13738. }
  13739. }
  13740. }
  13741. }
  13742. return $return;
  13743. }
  13744. public static function element_implode($element)
  13745. {
  13746. $full = "<$element[tag]";
  13747. foreach ($element['attribs'] as $key => $value)
  13748. {
  13749. $key = strtolower($key);
  13750. $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
  13751. }
  13752. if ($element['self_closing'])
  13753. {
  13754. $full .= ' />';
  13755. }
  13756. else
  13757. {
  13758. $full .= ">$element[content]</$element[tag]>";
  13759. }
  13760. return $full;
  13761. }
  13762. public static function error($message, $level, $file, $line)
  13763. {
  13764. if ((ini_get('error_reporting') & $level) > 0)
  13765. {
  13766. switch ($level)
  13767. {
  13768. case E_USER_ERROR:
  13769. $note = 'PHP Error';
  13770. break;
  13771. case E_USER_WARNING:
  13772. $note = 'PHP Warning';
  13773. break;
  13774. case E_USER_NOTICE:
  13775. $note = 'PHP Notice';
  13776. break;
  13777. default:
  13778. $note = 'Unknown Error';
  13779. break;
  13780. }
  13781. $log_error = true;
  13782. if (!function_exists('error_log'))
  13783. {
  13784. $log_error = false;
  13785. }
  13786. $log_file = @ini_get('error_log');
  13787. if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
  13788. {
  13789. $log_error = false;
  13790. }
  13791. if ($log_error)
  13792. {
  13793. @error_log("$note: $message in $file on line $line", 0);
  13794. }
  13795. }
  13796. return $message;
  13797. }
  13798. public static function fix_protocol($url, $http = 1)
  13799. {
  13800. $url = SimplePie_Misc::normalize_url($url);
  13801. $parsed = SimplePie_Misc::parse_url($url);
  13802. if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
  13803. {
  13804. return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
  13805. }
  13806. if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
  13807. {
  13808. return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
  13809. }
  13810. if ($http === 2 && $parsed['scheme'] !== '')
  13811. {
  13812. return "feed:$url";
  13813. }
  13814. elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
  13815. {
  13816. return substr_replace($url, 'podcast', 0, 4);
  13817. }
  13818. elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
  13819. {
  13820. return substr_replace($url, 'itpc', 0, 4);
  13821. }
  13822. else
  13823. {
  13824. return $url;
  13825. }
  13826. }
  13827. public static function array_merge_recursive($array1, $array2)
  13828. {
  13829. foreach ($array2 as $key => $value)
  13830. {
  13831. if (is_array($value))
  13832. {
  13833. $array1[$key] = SimplePie_Misc::array_merge_recursive($array1[$key], $value);
  13834. }
  13835. else
  13836. {
  13837. $array1[$key] = $value;
  13838. }
  13839. }
  13840. return $array1;
  13841. }
  13842. public static function parse_url($url)
  13843. {
  13844. $iri = new SimplePie_IRI($url);
  13845. return array(
  13846. 'scheme' => (string) $iri->scheme,
  13847. 'authority' => (string) $iri->authority,
  13848. 'path' => (string) $iri->path,
  13849. 'query' => (string) $iri->query,
  13850. 'fragment' => (string) $iri->fragment
  13851. );
  13852. }
  13853. public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
  13854. {
  13855. $iri = new SimplePie_IRI('');
  13856. $iri->scheme = $scheme;
  13857. $iri->authority = $authority;
  13858. $iri->path = $path;
  13859. $iri->query = $query;
  13860. $iri->fragment = $fragment;
  13861. return $iri->get_uri();
  13862. }
  13863. public static function normalize_url($url)
  13864. {
  13865. $iri = new SimplePie_IRI($url);
  13866. return $iri->get_uri();
  13867. }
  13868. public static function percent_encoding_normalization($match)
  13869. {
  13870. $integer = hexdec($match[1]);
  13871. if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
  13872. {
  13873. return chr($integer);
  13874. }
  13875. else
  13876. {
  13877. return strtoupper($match[0]);
  13878. }
  13879. }
  13880. /**
  13881. * Converts a Windows-1252 encoded string to a UTF-8 encoded string
  13882. *
  13883. * @static
  13884. * @param string $string Windows-1252 encoded string
  13885. * @return string UTF-8 encoded string
  13886. */
  13887. public static function windows_1252_to_utf8($string)
  13888. {
  13889. 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");
  13890. return strtr($string, $convert_table);
  13891. }
  13892. /**
  13893. * Change a string from one encoding to another
  13894. *
  13895. * @param string $data Raw data in $input encoding
  13896. * @param string $input Encoding of $data
  13897. * @param string $output Encoding you want
  13898. * @return string|boolean False if we can't convert it
  13899. */
  13900. public static function change_encoding($data, $input, $output)
  13901. {
  13902. $input = SimplePie_Misc::encoding($input);
  13903. $output = SimplePie_Misc::encoding($output);
  13904. // We fail to fail on non US-ASCII bytes
  13905. if ($input === 'US-ASCII')
  13906. {
  13907. static $non_ascii_octects = '';
  13908. if (!$non_ascii_octects)
  13909. {
  13910. for ($i = 0x80; $i <= 0xFF; $i++)
  13911. {
  13912. $non_ascii_octects .= chr($i);
  13913. }
  13914. }
  13915. $data = substr($data, 0, strcspn($data, $non_ascii_octects));
  13916. }
  13917. // This is first, as behaviour of this is completely predictable
  13918. if ($input === 'windows-1252' && $output === 'UTF-8')
  13919. {
  13920. return SimplePie_Misc::windows_1252_to_utf8($data);
  13921. }
  13922. // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
  13923. elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
  13924. {
  13925. return $return;
  13926. }
  13927. // This is last, as behaviour of this varies with OS userland and PHP version
  13928. elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
  13929. {
  13930. return $return;
  13931. }
  13932. // If we can't do anything, just fail
  13933. else
  13934. {
  13935. return false;
  13936. }
  13937. }
  13938. protected static function change_encoding_mbstring($data, $input, $output)
  13939. {
  13940. if ($input === 'windows-949')
  13941. {
  13942. $input = 'EUC-KR';
  13943. }
  13944. if ($output === 'windows-949')
  13945. {
  13946. $output = 'EUC-KR';
  13947. }
  13948. if ($input === 'Windows-31J')
  13949. {
  13950. $input = 'SJIS';
  13951. }
  13952. if ($output === 'Windows-31J')
  13953. {
  13954. $output = 'SJIS';
  13955. }
  13956. // Check that the encoding is supported
  13957. if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
  13958. {
  13959. return false;
  13960. }
  13961. if (!in_array($input, mb_list_encodings()))
  13962. {
  13963. return false;
  13964. }
  13965. // Let's do some conversion
  13966. if ($return = @mb_convert_encoding($data, $output, $input))
  13967. {
  13968. return $return;
  13969. }
  13970. return false;
  13971. }
  13972. protected static function change_encoding_iconv($data, $input, $output)
  13973. {
  13974. return @iconv($input, $output, $data);
  13975. }
  13976. /**
  13977. * Normalize an encoding name
  13978. *
  13979. * This is automatically generated by create.php
  13980. *
  13981. * To generate it, run `php create.php` on the command line, and copy the
  13982. * output to replace this function.
  13983. *
  13984. * @param string $charset Character set to standardise
  13985. * @return string Standardised name
  13986. */
  13987. public static function encoding($charset)
  13988. {
  13989. // Normalization from UTS #22
  13990. switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
  13991. {
  13992. case 'adobestandardencoding':
  13993. case 'csadobestandardencoding':
  13994. return 'Adobe-Standard-Encoding';
  13995. case 'adobesymbolencoding':
  13996. case 'cshppsmath':
  13997. return 'Adobe-Symbol-Encoding';
  13998. case 'ami1251':
  13999. case 'amiga1251':
  14000. return 'Amiga-1251';
  14001. case 'ansix31101983':
  14002. case 'csat5001983':
  14003. case 'csiso99naplps':
  14004. case 'isoir99':
  14005. case 'naplps':
  14006. return 'ANSI_X3.110-1983';
  14007. case 'arabic7':
  14008. case 'asmo449':
  14009. case 'csiso89asmo449':
  14010. case 'iso9036':
  14011. case 'isoir89':
  14012. return 'ASMO_449';
  14013. case 'big5':
  14014. case 'csbig5':
  14015. return 'Big5';
  14016. case 'big5hkscs':
  14017. return 'Big5-HKSCS';
  14018. case 'bocu1':
  14019. case 'csbocu1':
  14020. return 'BOCU-1';
  14021. case 'brf':
  14022. case 'csbrf':
  14023. return 'BRF';
  14024. case 'bs4730':
  14025. case 'csiso4unitedkingdom':
  14026. case 'gb':
  14027. case 'iso646gb':
  14028. case 'isoir4':
  14029. case 'uk':
  14030. return 'BS_4730';
  14031. case 'bsviewdata':
  14032. case 'csiso47bsviewdata':
  14033. case 'isoir47':
  14034. return 'BS_viewdata';
  14035. case 'cesu8':
  14036. case 'cscesu8':
  14037. return 'CESU-8';
  14038. case 'ca':
  14039. case 'csa71':
  14040. case 'csaz243419851':
  14041. case 'csiso121canadian1':
  14042. case 'iso646ca':
  14043. case 'isoir121':
  14044. return 'CSA_Z243.4-1985-1';
  14045. case 'csa72':
  14046. case 'csaz243419852':
  14047. case 'csiso122canadian2':
  14048. case 'iso646ca2':
  14049. case 'isoir122':
  14050. return 'CSA_Z243.4-1985-2';
  14051. case 'csaz24341985gr':
  14052. case 'csiso123csaz24341985gr':
  14053. case 'isoir123':
  14054. return 'CSA_Z243.4-1985-gr';
  14055. case 'csiso139csn369103':
  14056. case 'csn369103':
  14057. case 'isoir139':
  14058. return 'CSN_369103';
  14059. case 'csdecmcs':
  14060. case 'dec':
  14061. case 'decmcs':
  14062. return 'DEC-MCS';
  14063. case 'csiso21german':
  14064. case 'de':
  14065. case 'din66003':
  14066. case 'iso646de':
  14067. case 'isoir21':
  14068. return 'DIN_66003';
  14069. case 'csdkus':
  14070. case 'dkus':
  14071. return 'dk-us';
  14072. case 'csiso646danish':
  14073. case 'dk':
  14074. case 'ds2089':
  14075. case 'iso646dk':
  14076. return 'DS_2089';
  14077. case 'csibmebcdicatde':
  14078. case 'ebcdicatde':
  14079. return 'EBCDIC-AT-DE';
  14080. case 'csebcdicatdea':
  14081. case 'ebcdicatdea':
  14082. return 'EBCDIC-AT-DE-A';
  14083. case 'csebcdiccafr':
  14084. case 'ebcdiccafr':
  14085. return 'EBCDIC-CA-FR';
  14086. case 'csebcdicdkno':
  14087. case 'ebcdicdkno':
  14088. return 'EBCDIC-DK-NO';
  14089. case 'csebcdicdknoa':
  14090. case 'ebcdicdknoa':
  14091. return 'EBCDIC-DK-NO-A';
  14092. case 'csebcdices':
  14093. case 'ebcdices':
  14094. return 'EBCDIC-ES';
  14095. case 'csebcdicesa':
  14096. case 'ebcdicesa':
  14097. return 'EBCDIC-ES-A';
  14098. case 'csebcdicess':
  14099. case 'ebcdicess':
  14100. return 'EBCDIC-ES-S';
  14101. case 'csebcdicfise':
  14102. case 'ebcdicfise':
  14103. return 'EBCDIC-FI-SE';
  14104. case 'csebcdicfisea':
  14105. case 'ebcdicfisea':
  14106. return 'EBCDIC-FI-SE-A';
  14107. case 'csebcdicfr':
  14108. case 'ebcdicfr':
  14109. return 'EBCDIC-FR';
  14110. case 'csebcdicit':
  14111. case 'ebcdicit':
  14112. return 'EBCDIC-IT';
  14113. case 'csebcdicpt':
  14114. case 'ebcdicpt':
  14115. return 'EBCDIC-PT';
  14116. case 'csebcdicuk':
  14117. case 'ebcdicuk':
  14118. return 'EBCDIC-UK';
  14119. case 'csebcdicus':
  14120. case 'ebcdicus':
  14121. return 'EBCDIC-US';
  14122. case 'csiso111ecmacyrillic':
  14123. case 'ecmacyrillic':
  14124. case 'isoir111':
  14125. case 'koi8e':
  14126. return 'ECMA-cyrillic';
  14127. case 'csiso17spanish':
  14128. case 'es':
  14129. case 'iso646es':
  14130. case 'isoir17':
  14131. return 'ES';
  14132. case 'csiso85spanish2':
  14133. case 'es2':
  14134. case 'iso646es2':
  14135. case 'isoir85':
  14136. return 'ES2';
  14137. case 'cseucpkdfmtjapanese':
  14138. case 'eucjp':
  14139. case 'extendedunixcodepackedformatforjapanese':
  14140. return 'EUC-JP';
  14141. case 'cseucfixwidjapanese':
  14142. case 'extendedunixcodefixedwidthforjapanese':
  14143. return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
  14144. case 'gb18030':
  14145. return 'GB18030';
  14146. case 'chinese':
  14147. case 'cp936':
  14148. case 'csgb2312':
  14149. case 'csiso58gb231280':
  14150. case 'gb2312':
  14151. case 'gb231280':
  14152. case 'gbk':
  14153. case 'isoir58':
  14154. case 'ms936':
  14155. case 'windows936':
  14156. return 'GBK';
  14157. case 'cn':
  14158. case 'csiso57gb1988':
  14159. case 'gb198880':
  14160. case 'iso646cn':
  14161. case 'isoir57':
  14162. return 'GB_1988-80';
  14163. case 'csiso153gost1976874':
  14164. case 'gost1976874':
  14165. case 'isoir153':
  14166. case 'stsev35888':
  14167. return 'GOST_19768-74';
  14168. case 'csiso150':
  14169. case 'csiso150greekccitt':
  14170. case 'greekccitt':
  14171. case 'isoir150':
  14172. return 'greek-ccitt';
  14173. case 'csiso88greek7':
  14174. case 'greek7':
  14175. case 'isoir88':
  14176. return 'greek7';
  14177. case 'csiso18greek7old':
  14178. case 'greek7old':
  14179. case 'isoir18':
  14180. return 'greek7-old';
  14181. case 'cshpdesktop':
  14182. case 'hpdesktop':
  14183. return 'HP-DeskTop';
  14184. case 'cshplegal':
  14185. case 'hplegal':
  14186. return 'HP-Legal';
  14187. case 'cshpmath8':
  14188. case 'hpmath8':
  14189. return 'HP-Math8';
  14190. case 'cshppifont':
  14191. case 'hppifont':
  14192. return 'HP-Pi-font';
  14193. case 'cshproman8':
  14194. case 'hproman8':
  14195. case 'r8':
  14196. case 'roman8':
  14197. return 'hp-roman8';
  14198. case 'hzgb2312':
  14199. return 'HZ-GB-2312';
  14200. case 'csibmsymbols':
  14201. case 'ibmsymbols':
  14202. return 'IBM-Symbols';
  14203. case 'csibmthai':
  14204. case 'ibmthai':
  14205. return 'IBM-Thai';
  14206. case 'cp37':
  14207. case 'csibm37':
  14208. case 'ebcdiccpca':
  14209. case 'ebcdiccpnl':
  14210. case 'ebcdiccpus':
  14211. case 'ebcdiccpwt':
  14212. case 'ibm37':
  14213. return 'IBM037';
  14214. case 'cp38':
  14215. case 'csibm38':
  14216. case 'ebcdicint':
  14217. case 'ibm38':
  14218. return 'IBM038';
  14219. case 'cp273':
  14220. case 'csibm273':
  14221. case 'ibm273':
  14222. return 'IBM273';
  14223. case 'cp274':
  14224. case 'csibm274':
  14225. case 'ebcdicbe':
  14226. case 'ibm274':
  14227. return 'IBM274';
  14228. case 'cp275':
  14229. case 'csibm275':
  14230. case 'ebcdicbr':
  14231. case 'ibm275':
  14232. return 'IBM275';
  14233. case 'csibm277':
  14234. case 'ebcdiccpdk':
  14235. case 'ebcdiccpno':
  14236. case 'ibm277':
  14237. return 'IBM277';
  14238. case 'cp278':
  14239. case 'csibm278':
  14240. case 'ebcdiccpfi':
  14241. case 'ebcdiccpse':
  14242. case 'ibm278':
  14243. return 'IBM278';
  14244. case 'cp280':
  14245. case 'csibm280':
  14246. case 'ebcdiccpit':
  14247. case 'ibm280':
  14248. return 'IBM280';
  14249. case 'cp281':
  14250. case 'csibm281':
  14251. case 'ebcdicjpe':
  14252. case 'ibm281':
  14253. return 'IBM281';
  14254. case 'cp284':
  14255. case 'csibm284':
  14256. case 'ebcdiccpes':
  14257. case 'ibm284':
  14258. return 'IBM284';
  14259. case 'cp285':
  14260. case 'csibm285':
  14261. case 'ebcdiccpgb':
  14262. case 'ibm285':
  14263. return 'IBM285';
  14264. case 'cp290':
  14265. case 'csibm290':
  14266. case 'ebcdicjpkana':
  14267. case 'ibm290':
  14268. return 'IBM290';
  14269. case 'cp297':
  14270. case 'csibm297':
  14271. case 'ebcdiccpfr':
  14272. case 'ibm297':
  14273. return 'IBM297';
  14274. case 'cp420':
  14275. case 'csibm420':
  14276. case 'ebcdiccpar1':
  14277. case 'ibm420':
  14278. return 'IBM420';
  14279. case 'cp423':
  14280. case 'csibm423':
  14281. case 'ebcdiccpgr':
  14282. case 'ibm423':
  14283. return 'IBM423';
  14284. case 'cp424':
  14285. case 'csibm424':
  14286. case 'ebcdiccphe':
  14287. case 'ibm424':
  14288. return 'IBM424';
  14289. case '437':
  14290. case 'cp437':
  14291. case 'cspc8codepage437':
  14292. case 'ibm437':
  14293. return 'IBM437';
  14294. case 'cp500':
  14295. case 'csibm500':
  14296. case 'ebcdiccpbe':
  14297. case 'ebcdiccpch':
  14298. case 'ibm500':
  14299. return 'IBM500';
  14300. case 'cp775':
  14301. case 'cspc775baltic':
  14302. case 'ibm775':
  14303. return 'IBM775';
  14304. case '850':
  14305. case 'cp850':
  14306. case 'cspc850multilingual':
  14307. case 'ibm850':
  14308. return 'IBM850';
  14309. case '851':
  14310. case 'cp851':
  14311. case 'csibm851':
  14312. case 'ibm851':
  14313. return 'IBM851';
  14314. case '852':
  14315. case 'cp852':
  14316. case 'cspcp852':
  14317. case 'ibm852':
  14318. return 'IBM852';
  14319. case '855':
  14320. case 'cp855':
  14321. case 'csibm855':
  14322. case 'ibm855':
  14323. return 'IBM855';
  14324. case '857':
  14325. case 'cp857':
  14326. case 'csibm857':
  14327. case 'ibm857':
  14328. return 'IBM857';
  14329. case 'ccsid858':
  14330. case 'cp858':
  14331. case 'ibm858':
  14332. case 'pcmultilingual850euro':
  14333. return 'IBM00858';
  14334. case '860':
  14335. case 'cp860':
  14336. case 'csibm860':
  14337. case 'ibm860':
  14338. return 'IBM860';
  14339. case '861':
  14340. case 'cp861':
  14341. case 'cpis':
  14342. case 'csibm861':
  14343. case 'ibm861':
  14344. return 'IBM861';
  14345. case '862':
  14346. case 'cp862':
  14347. case 'cspc862latinhebrew':
  14348. case 'ibm862':
  14349. return 'IBM862';
  14350. case '863':
  14351. case 'cp863':
  14352. case 'csibm863':
  14353. case 'ibm863':
  14354. return 'IBM863';
  14355. case 'cp864':
  14356. case 'csibm864':
  14357. case 'ibm864':
  14358. return 'IBM864';
  14359. case '865':
  14360. case 'cp865':
  14361. case 'csibm865':
  14362. case 'ibm865':
  14363. return 'IBM865';
  14364. case '866':
  14365. case 'cp866':
  14366. case 'csibm866':
  14367. case 'ibm866':
  14368. return 'IBM866';
  14369. case 'cp868':
  14370. case 'cpar':
  14371. case 'csibm868':
  14372. case 'ibm868':
  14373. return 'IBM868';
  14374. case '869':
  14375. case 'cp869':
  14376. case 'cpgr':
  14377. case 'csibm869':
  14378. case 'ibm869':
  14379. return 'IBM869';
  14380. case 'cp870':
  14381. case 'csibm870':
  14382. case 'ebcdiccproece':
  14383. case 'ebcdiccpyu':
  14384. case 'ibm870':
  14385. return 'IBM870';
  14386. case 'cp871':
  14387. case 'csibm871':
  14388. case 'ebcdiccpis':
  14389. case 'ibm871':
  14390. return 'IBM871';
  14391. case 'cp880':
  14392. case 'csibm880':
  14393. case 'ebcdiccyrillic':
  14394. case 'ibm880':
  14395. return 'IBM880';
  14396. case 'cp891':
  14397. case 'csibm891':
  14398. case 'ibm891':
  14399. return 'IBM891';
  14400. case 'cp903':
  14401. case 'csibm903':
  14402. case 'ibm903':
  14403. return 'IBM903';
  14404. case '904':
  14405. case 'cp904':
  14406. case 'csibbm904':
  14407. case 'ibm904':
  14408. return 'IBM904';
  14409. case 'cp905':
  14410. case 'csibm905':
  14411. case 'ebcdiccptr':
  14412. case 'ibm905':
  14413. return 'IBM905';
  14414. case 'cp918':
  14415. case 'csibm918':
  14416. case 'ebcdiccpar2':
  14417. case 'ibm918':
  14418. return 'IBM918';
  14419. case 'ccsid924':
  14420. case 'cp924':
  14421. case 'ebcdiclatin9euro':
  14422. case 'ibm924':
  14423. return 'IBM00924';
  14424. case 'cp1026':
  14425. case 'csibm1026':
  14426. case 'ibm1026':
  14427. return 'IBM1026';
  14428. case 'ibm1047':
  14429. return 'IBM1047';
  14430. case 'ccsid1140':
  14431. case 'cp1140':
  14432. case 'ebcdicus37euro':
  14433. case 'ibm1140':
  14434. return 'IBM01140';
  14435. case 'ccsid1141':
  14436. case 'cp1141':
  14437. case 'ebcdicde273euro':
  14438. case 'ibm1141':
  14439. return 'IBM01141';
  14440. case 'ccsid1142':
  14441. case 'cp1142':
  14442. case 'ebcdicdk277euro':
  14443. case 'ebcdicno277euro':
  14444. case 'ibm1142':
  14445. return 'IBM01142';
  14446. case 'ccsid1143':
  14447. case 'cp1143':
  14448. case 'ebcdicfi278euro':
  14449. case 'ebcdicse278euro':
  14450. case 'ibm1143':
  14451. return 'IBM01143';
  14452. case 'ccsid1144':
  14453. case 'cp1144':
  14454. case 'ebcdicit280euro':
  14455. case 'ibm1144':
  14456. return 'IBM01144';
  14457. case 'ccsid1145':
  14458. case 'cp1145':
  14459. case 'ebcdices284euro':
  14460. case 'ibm1145':
  14461. return 'IBM01145';
  14462. case 'ccsid1146':
  14463. case 'cp1146':
  14464. case 'ebcdicgb285euro':
  14465. case 'ibm1146':
  14466. return 'IBM01146';
  14467. case 'ccsid1147':
  14468. case 'cp1147':
  14469. case 'ebcdicfr297euro':
  14470. case 'ibm1147':
  14471. return 'IBM01147';
  14472. case 'ccsid1148':
  14473. case 'cp1148':
  14474. case 'ebcdicinternational500euro':
  14475. case 'ibm1148':
  14476. return 'IBM01148';
  14477. case 'ccsid1149':
  14478. case 'cp1149':
  14479. case 'ebcdicis871euro':
  14480. case 'ibm1149':
  14481. return 'IBM01149';
  14482. case 'csiso143iecp271':
  14483. case 'iecp271':
  14484. case 'isoir143':
  14485. return 'IEC_P27-1';
  14486. case 'csiso49inis':
  14487. case 'inis':
  14488. case 'isoir49':
  14489. return 'INIS';
  14490. case 'csiso50inis8':
  14491. case 'inis8':
  14492. case 'isoir50':
  14493. return 'INIS-8';
  14494. case 'csiso51iniscyrillic':
  14495. case 'iniscyrillic':
  14496. case 'isoir51':
  14497. return 'INIS-cyrillic';
  14498. case 'csinvariant':
  14499. case 'invariant':
  14500. return 'INVARIANT';
  14501. case 'iso2022cn':
  14502. return 'ISO-2022-CN';
  14503. case 'iso2022cnext':
  14504. return 'ISO-2022-CN-EXT';
  14505. case 'csiso2022jp':
  14506. case 'iso2022jp':
  14507. return 'ISO-2022-JP';
  14508. case 'csiso2022jp2':
  14509. case 'iso2022jp2':
  14510. return 'ISO-2022-JP-2';
  14511. case 'csiso2022kr':
  14512. case 'iso2022kr':
  14513. return 'ISO-2022-KR';
  14514. case 'cswindows30latin1':
  14515. case 'iso88591windows30latin1':
  14516. return 'ISO-8859-1-Windows-3.0-Latin-1';
  14517. case 'cswindows31latin1':
  14518. case 'iso88591windows31latin1':
  14519. return 'ISO-8859-1-Windows-3.1-Latin-1';
  14520. case 'csisolatin2':
  14521. case 'iso88592':
  14522. case 'iso885921987':
  14523. case 'isoir101':
  14524. case 'l2':
  14525. case 'latin2':
  14526. return 'ISO-8859-2';
  14527. case 'cswindows31latin2':
  14528. case 'iso88592windowslatin2':
  14529. return 'ISO-8859-2-Windows-Latin-2';
  14530. case 'csisolatin3':
  14531. case 'iso88593':
  14532. case 'iso885931988':
  14533. case 'isoir109':
  14534. case 'l3':
  14535. case 'latin3':
  14536. return 'ISO-8859-3';
  14537. case 'csisolatin4':
  14538. case 'iso88594':
  14539. case 'iso885941988':
  14540. case 'isoir110':
  14541. case 'l4':
  14542. case 'latin4':
  14543. return 'ISO-8859-4';
  14544. case 'csisolatincyrillic':
  14545. case 'cyrillic':
  14546. case 'iso88595':
  14547. case 'iso885951988':
  14548. case 'isoir144':
  14549. return 'ISO-8859-5';
  14550. case 'arabic':
  14551. case 'asmo708':
  14552. case 'csisolatinarabic':
  14553. case 'ecma114':
  14554. case 'iso88596':
  14555. case 'iso885961987':
  14556. case 'isoir127':
  14557. return 'ISO-8859-6';
  14558. case 'csiso88596e':
  14559. case 'iso88596e':
  14560. return 'ISO-8859-6-E';
  14561. case 'csiso88596i':
  14562. case 'iso88596i':
  14563. return 'ISO-8859-6-I';
  14564. case 'csisolatingreek':
  14565. case 'ecma118':
  14566. case 'elot928':
  14567. case 'greek':
  14568. case 'greek8':
  14569. case 'iso88597':
  14570. case 'iso885971987':
  14571. case 'isoir126':
  14572. return 'ISO-8859-7';
  14573. case 'csisolatinhebrew':
  14574. case 'hebrew':
  14575. case 'iso88598':
  14576. case 'iso885981988':
  14577. case 'isoir138':
  14578. return 'ISO-8859-8';
  14579. case 'csiso88598e':
  14580. case 'iso88598e':
  14581. return 'ISO-8859-8-E';
  14582. case 'csiso88598i':
  14583. case 'iso88598i':
  14584. return 'ISO-8859-8-I';
  14585. case 'cswindows31latin5':
  14586. case 'iso88599windowslatin5':
  14587. return 'ISO-8859-9-Windows-Latin-5';
  14588. case 'csisolatin6':
  14589. case 'iso885910':
  14590. case 'iso8859101992':
  14591. case 'isoir157':
  14592. case 'l6':
  14593. case 'latin6':
  14594. return 'ISO-8859-10';
  14595. case 'iso885913':
  14596. return 'ISO-8859-13';
  14597. case 'iso885914':
  14598. case 'iso8859141998':
  14599. case 'isoceltic':
  14600. case 'isoir199':
  14601. case 'l8':
  14602. case 'latin8':
  14603. return 'ISO-8859-14';
  14604. case 'iso885915':
  14605. case 'latin9':
  14606. return 'ISO-8859-15';
  14607. case 'iso885916':
  14608. case 'iso8859162001':
  14609. case 'isoir226':
  14610. case 'l10':
  14611. case 'latin10':
  14612. return 'ISO-8859-16';
  14613. case 'iso10646j1':
  14614. return 'ISO-10646-J-1';
  14615. case 'csunicode':
  14616. case 'iso10646ucs2':
  14617. return 'ISO-10646-UCS-2';
  14618. case 'csucs4':
  14619. case 'iso10646ucs4':
  14620. return 'ISO-10646-UCS-4';
  14621. case 'csunicodeascii':
  14622. case 'iso10646ucsbasic':
  14623. return 'ISO-10646-UCS-Basic';
  14624. case 'csunicodelatin1':
  14625. case 'iso10646':
  14626. case 'iso10646unicodelatin1':
  14627. return 'ISO-10646-Unicode-Latin1';
  14628. case 'csiso10646utf1':
  14629. case 'iso10646utf1':
  14630. return 'ISO-10646-UTF-1';
  14631. case 'csiso115481':
  14632. case 'iso115481':
  14633. case 'isotr115481':
  14634. return 'ISO-11548-1';
  14635. case 'csiso90':
  14636. case 'isoir90':
  14637. return 'iso-ir-90';
  14638. case 'csunicodeibm1261':
  14639. case 'isounicodeibm1261':
  14640. return 'ISO-Unicode-IBM-1261';
  14641. case 'csunicodeibm1264':
  14642. case 'isounicodeibm1264':
  14643. return 'ISO-Unicode-IBM-1264';
  14644. case 'csunicodeibm1265':
  14645. case 'isounicodeibm1265':
  14646. return 'ISO-Unicode-IBM-1265';
  14647. case 'csunicodeibm1268':
  14648. case 'isounicodeibm1268':
  14649. return 'ISO-Unicode-IBM-1268';
  14650. case 'csunicodeibm1276':
  14651. case 'isounicodeibm1276':
  14652. return 'ISO-Unicode-IBM-1276';
  14653. case 'csiso646basic1983':
  14654. case 'iso646basic1983':
  14655. case 'ref':
  14656. return 'ISO_646.basic:1983';
  14657. case 'csiso2intlrefversion':
  14658. case 'irv':
  14659. case 'iso646irv1983':
  14660. case 'isoir2':
  14661. return 'ISO_646.irv:1983';
  14662. case 'csiso2033':
  14663. case 'e13b':
  14664. case 'iso20331983':
  14665. case 'isoir98':
  14666. return 'ISO_2033-1983';
  14667. case 'csiso5427cyrillic':
  14668. case 'iso5427':
  14669. case 'isoir37':
  14670. return 'ISO_5427';
  14671. case 'iso5427cyrillic1981':
  14672. case 'iso54271981':
  14673. case 'isoir54':
  14674. return 'ISO_5427:1981';
  14675. case 'csiso5428greek':
  14676. case 'iso54281980':
  14677. case 'isoir55':
  14678. return 'ISO_5428:1980';
  14679. case 'csiso6937add':
  14680. case 'iso6937225':
  14681. case 'isoir152':
  14682. return 'ISO_6937-2-25';
  14683. case 'csisotextcomm':
  14684. case 'iso69372add':
  14685. case 'isoir142':
  14686. return 'ISO_6937-2-add';
  14687. case 'csiso8859supp':
  14688. case 'iso8859supp':
  14689. case 'isoir154':
  14690. case 'latin125':
  14691. return 'ISO_8859-supp';
  14692. case 'csiso10367box':
  14693. case 'iso10367box':
  14694. case 'isoir155':
  14695. return 'ISO_10367-box';
  14696. case 'csiso15italian':
  14697. case 'iso646it':
  14698. case 'isoir15':
  14699. case 'it':
  14700. return 'IT';
  14701. case 'csiso13jisc6220jp':
  14702. case 'isoir13':
  14703. case 'jisc62201969':
  14704. case 'jisc62201969jp':
  14705. case 'katakana':
  14706. case 'x2017':
  14707. return 'JIS_C6220-1969-jp';
  14708. case 'csiso14jisc6220ro':
  14709. case 'iso646jp':
  14710. case 'isoir14':
  14711. case 'jisc62201969ro':
  14712. case 'jp':
  14713. return 'JIS_C6220-1969-ro';
  14714. case 'csiso42jisc62261978':
  14715. case 'isoir42':
  14716. case 'jisc62261978':
  14717. return 'JIS_C6226-1978';
  14718. case 'csiso87jisx208':
  14719. case 'isoir87':
  14720. case 'jisc62261983':
  14721. case 'jisx2081983':
  14722. case 'x208':
  14723. return 'JIS_C6226-1983';
  14724. case 'csiso91jisc62291984a':
  14725. case 'isoir91':
  14726. case 'jisc62291984a':
  14727. case 'jpocra':
  14728. return 'JIS_C6229-1984-a';
  14729. case 'csiso92jisc62991984b':
  14730. case 'iso646jpocrb':
  14731. case 'isoir92':
  14732. case 'jisc62291984b':
  14733. case 'jpocrb':
  14734. return 'JIS_C6229-1984-b';
  14735. case 'csiso93jis62291984badd':
  14736. case 'isoir93':
  14737. case 'jisc62291984badd':
  14738. case 'jpocrbadd':
  14739. return 'JIS_C6229-1984-b-add';
  14740. case 'csiso94jis62291984hand':
  14741. case 'isoir94':
  14742. case 'jisc62291984hand':
  14743. case 'jpocrhand':
  14744. return 'JIS_C6229-1984-hand';
  14745. case 'csiso95jis62291984handadd':
  14746. case 'isoir95':
  14747. case 'jisc62291984handadd':
  14748. case 'jpocrhandadd':
  14749. return 'JIS_C6229-1984-hand-add';
  14750. case 'csiso96jisc62291984kana':
  14751. case 'isoir96':
  14752. case 'jisc62291984kana':
  14753. return 'JIS_C6229-1984-kana';
  14754. case 'csjisencoding':
  14755. case 'jisencoding':
  14756. return 'JIS_Encoding';
  14757. case 'cshalfwidthkatakana':
  14758. case 'jisx201':
  14759. case 'x201':
  14760. return 'JIS_X0201';
  14761. case 'csiso159jisx2121990':
  14762. case 'isoir159':
  14763. case 'jisx2121990':
  14764. case 'x212':
  14765. return 'JIS_X0212-1990';
  14766. case 'csiso141jusib1002':
  14767. case 'iso646yu':
  14768. case 'isoir141':
  14769. case 'js':
  14770. case 'jusib1002':
  14771. case 'yu':
  14772. return 'JUS_I.B1.002';
  14773. case 'csiso147macedonian':
  14774. case 'isoir147':
  14775. case 'jusib1003mac':
  14776. case 'macedonian':
  14777. return 'JUS_I.B1.003-mac';
  14778. case 'csiso146serbian':
  14779. case 'isoir146':
  14780. case 'jusib1003serb':
  14781. case 'serbian':
  14782. return 'JUS_I.B1.003-serb';
  14783. case 'koi7switched':
  14784. return 'KOI7-switched';
  14785. case 'cskoi8r':
  14786. case 'koi8r':
  14787. return 'KOI8-R';
  14788. case 'koi8u':
  14789. return 'KOI8-U';
  14790. case 'csksc5636':
  14791. case 'iso646kr':
  14792. case 'ksc5636':
  14793. return 'KSC5636';
  14794. case 'cskz1048':
  14795. case 'kz1048':
  14796. case 'rk1048':
  14797. case 'strk10482002':
  14798. return 'KZ-1048';
  14799. case 'csiso19latingreek':
  14800. case 'isoir19':
  14801. case 'latingreek':
  14802. return 'latin-greek';
  14803. case 'csiso27latingreek1':
  14804. case 'isoir27':
  14805. case 'latingreek1':
  14806. return 'Latin-greek-1';
  14807. case 'csiso158lap':
  14808. case 'isoir158':
  14809. case 'lap':
  14810. case 'latinlap':
  14811. return 'latin-lap';
  14812. case 'csmacintosh':
  14813. case 'mac':
  14814. case 'macintosh':
  14815. return 'macintosh';
  14816. case 'csmicrosoftpublishing':
  14817. case 'microsoftpublishing':
  14818. return 'Microsoft-Publishing';
  14819. case 'csmnem':
  14820. case 'mnem':
  14821. return 'MNEM';
  14822. case 'csmnemonic':
  14823. case 'mnemonic':
  14824. return 'MNEMONIC';
  14825. case 'csiso86hungarian':
  14826. case 'hu':
  14827. case 'iso646hu':
  14828. case 'isoir86':
  14829. case 'msz77953':
  14830. return 'MSZ_7795.3';
  14831. case 'csnatsdano':
  14832. case 'isoir91':
  14833. case 'natsdano':
  14834. return 'NATS-DANO';
  14835. case 'csnatsdanoadd':
  14836. case 'isoir92':
  14837. case 'natsdanoadd':
  14838. return 'NATS-DANO-ADD';
  14839. case 'csnatssefi':
  14840. case 'isoir81':
  14841. case 'natssefi':
  14842. return 'NATS-SEFI';
  14843. case 'csnatssefiadd':
  14844. case 'isoir82':
  14845. case 'natssefiadd':
  14846. return 'NATS-SEFI-ADD';
  14847. case 'csiso151cuba':
  14848. case 'cuba':
  14849. case 'iso646cu':
  14850. case 'isoir151':
  14851. case 'ncnc1081':
  14852. return 'NC_NC00-10:81';
  14853. case 'csiso69french':
  14854. case 'fr':
  14855. case 'iso646fr':
  14856. case 'isoir69':
  14857. case 'nfz62010':
  14858. return 'NF_Z_62-010';
  14859. case 'csiso25french':
  14860. case 'iso646fr1':
  14861. case 'isoir25':
  14862. case 'nfz620101973':
  14863. return 'NF_Z_62-010_(1973)';
  14864. case 'csiso60danishnorwegian':
  14865. case 'csiso60norwegian1':
  14866. case 'iso646no':
  14867. case 'isoir60':
  14868. case 'no':
  14869. case 'ns45511':
  14870. return 'NS_4551-1';
  14871. case 'csiso61norwegian2':
  14872. case 'iso646no2':
  14873. case 'isoir61':
  14874. case 'no2':
  14875. case 'ns45512':
  14876. return 'NS_4551-2';
  14877. case 'osdebcdicdf3irv':
  14878. return 'OSD_EBCDIC_DF03_IRV';
  14879. case 'osdebcdicdf41':
  14880. return 'OSD_EBCDIC_DF04_1';
  14881. case 'osdebcdicdf415':
  14882. return 'OSD_EBCDIC_DF04_15';
  14883. case 'cspc8danishnorwegian':
  14884. case 'pc8danishnorwegian':
  14885. return 'PC8-Danish-Norwegian';
  14886. case 'cspc8turkish':
  14887. case 'pc8turkish':
  14888. return 'PC8-Turkish';
  14889. case 'csiso16portuguese':
  14890. case 'iso646pt':
  14891. case 'isoir16':
  14892. case 'pt':
  14893. return 'PT';
  14894. case 'csiso84portuguese2':
  14895. case 'iso646pt2':
  14896. case 'isoir84':
  14897. case 'pt2':
  14898. return 'PT2';
  14899. case 'cp154':
  14900. case 'csptcp154':
  14901. case 'cyrillicasian':
  14902. case 'pt154':
  14903. case 'ptcp154':
  14904. return 'PTCP154';
  14905. case 'scsu':
  14906. return 'SCSU';
  14907. case 'csiso10swedish':
  14908. case 'fi':
  14909. case 'iso646fi':
  14910. case 'iso646se':
  14911. case 'isoir10':
  14912. case 'se':
  14913. case 'sen850200b':
  14914. return 'SEN_850200_B';
  14915. case 'csiso11swedishfornames':
  14916. case 'iso646se2':
  14917. case 'isoir11':
  14918. case 'se2':
  14919. case 'sen850200c':
  14920. return 'SEN_850200_C';
  14921. case 'csiso102t617bit':
  14922. case 'isoir102':
  14923. case 't617bit':
  14924. return 'T.61-7bit';
  14925. case 'csiso103t618bit':
  14926. case 'isoir103':
  14927. case 't61':
  14928. case 't618bit':
  14929. return 'T.61-8bit';
  14930. case 'csiso128t101g2':
  14931. case 'isoir128':
  14932. case 't101g2':
  14933. return 'T.101-G2';
  14934. case 'cstscii':
  14935. case 'tscii':
  14936. return 'TSCII';
  14937. case 'csunicode11':
  14938. case 'unicode11':
  14939. return 'UNICODE-1-1';
  14940. case 'csunicode11utf7':
  14941. case 'unicode11utf7':
  14942. return 'UNICODE-1-1-UTF-7';
  14943. case 'csunknown8bit':
  14944. case 'unknown8bit':
  14945. return 'UNKNOWN-8BIT';
  14946. case 'ansix341968':
  14947. case 'ansix341986':
  14948. case 'ascii':
  14949. case 'cp367':
  14950. case 'csascii':
  14951. case 'ibm367':
  14952. case 'iso646irv1991':
  14953. case 'iso646us':
  14954. case 'isoir6':
  14955. case 'us':
  14956. case 'usascii':
  14957. return 'US-ASCII';
  14958. case 'csusdk':
  14959. case 'usdk':
  14960. return 'us-dk';
  14961. case 'utf7':
  14962. return 'UTF-7';
  14963. case 'utf8':
  14964. return 'UTF-8';
  14965. case 'utf16':
  14966. return 'UTF-16';
  14967. case 'utf16be':
  14968. return 'UTF-16BE';
  14969. case 'utf16le':
  14970. return 'UTF-16LE';
  14971. case 'utf32':
  14972. return 'UTF-32';
  14973. case 'utf32be':
  14974. return 'UTF-32BE';
  14975. case 'utf32le':
  14976. return 'UTF-32LE';
  14977. case 'csventurainternational':
  14978. case 'venturainternational':
  14979. return 'Ventura-International';
  14980. case 'csventuramath':
  14981. case 'venturamath':
  14982. return 'Ventura-Math';
  14983. case 'csventuraus':
  14984. case 'venturaus':
  14985. return 'Ventura-US';
  14986. case 'csiso70videotexsupp1':
  14987. case 'isoir70':
  14988. case 'videotexsuppl':
  14989. return 'videotex-suppl';
  14990. case 'csviqr':
  14991. case 'viqr':
  14992. return 'VIQR';
  14993. case 'csviscii':
  14994. case 'viscii':
  14995. return 'VISCII';
  14996. case 'csshiftjis':
  14997. case 'cswindows31j':
  14998. case 'mskanji':
  14999. case 'shiftjis':
  15000. case 'windows31j':
  15001. return 'Windows-31J';
  15002. case 'iso885911':
  15003. case 'tis620':
  15004. return 'windows-874';
  15005. case 'cseuckr':
  15006. case 'csksc56011987':
  15007. case 'euckr':
  15008. case 'isoir149':
  15009. case 'korean':
  15010. case 'ksc5601':
  15011. case 'ksc56011987':
  15012. case 'ksc56011989':
  15013. case 'windows949':
  15014. return 'windows-949';
  15015. case 'windows1250':
  15016. return 'windows-1250';
  15017. case 'windows1251':
  15018. return 'windows-1251';
  15019. case 'cp819':
  15020. case 'csisolatin1':
  15021. case 'ibm819':
  15022. case 'iso88591':
  15023. case 'iso885911987':
  15024. case 'isoir100':
  15025. case 'l1':
  15026. case 'latin1':
  15027. case 'windows1252':
  15028. return 'windows-1252';
  15029. case 'windows1253':
  15030. return 'windows-1253';
  15031. case 'csisolatin5':
  15032. case 'iso88599':
  15033. case 'iso885991989':
  15034. case 'isoir148':
  15035. case 'l5':
  15036. case 'latin5':
  15037. case 'windows1254':
  15038. return 'windows-1254';
  15039. case 'windows1255':
  15040. return 'windows-1255';
  15041. case 'windows1256':
  15042. return 'windows-1256';
  15043. case 'windows1257':
  15044. return 'windows-1257';
  15045. case 'windows1258':
  15046. return 'windows-1258';
  15047. default:
  15048. return $charset;
  15049. }
  15050. }
  15051. public static function get_curl_version()
  15052. {
  15053. if (is_array($curl = curl_version()))
  15054. {
  15055. $curl = $curl['version'];
  15056. }
  15057. elseif (substr($curl, 0, 5) === 'curl/')
  15058. {
  15059. $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
  15060. }
  15061. elseif (substr($curl, 0, 8) === 'libcurl/')
  15062. {
  15063. $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
  15064. }
  15065. else
  15066. {
  15067. $curl = 0;
  15068. }
  15069. return $curl;
  15070. }
  15071. /**
  15072. * Strip HTML comments
  15073. *
  15074. * @param string $data Data to strip comments from
  15075. * @return string Comment stripped string
  15076. */
  15077. public static function strip_comments($data)
  15078. {
  15079. $output = '';
  15080. while (($start = strpos($data, '<!--')) !== false)
  15081. {
  15082. $output .= substr($data, 0, $start);
  15083. if (($end = strpos($data, '-->', $start)) !== false)
  15084. {
  15085. $data = substr_replace($data, '', 0, $end + 3);
  15086. }
  15087. else
  15088. {
  15089. $data = '';
  15090. }
  15091. }
  15092. return $output . $data;
  15093. }
  15094. public static function parse_date($dt)
  15095. {
  15096. $parser = SimplePie_Parse_Date::get();
  15097. return $parser->parse($dt);
  15098. }
  15099. /**
  15100. * Decode HTML entities
  15101. *
  15102. * @deprecated Use DOMDocument instead
  15103. * @param string $data Input data
  15104. * @return string Output data
  15105. */
  15106. public static function entities_decode($data)
  15107. {
  15108. $decoder = new SimplePie_Decode_HTML_Entities($data);
  15109. return $decoder->parse();
  15110. }
  15111. /**
  15112. * Remove RFC822 comments
  15113. *
  15114. * @param string $data Data to strip comments from
  15115. * @return string Comment stripped string
  15116. */
  15117. public static function uncomment_rfc822($string)
  15118. {
  15119. $string = (string) $string;
  15120. $position = 0;
  15121. $length = strlen($string);
  15122. $depth = 0;
  15123. $output = '';
  15124. while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
  15125. {
  15126. $output .= substr($string, $position, $pos - $position);
  15127. $position = $pos + 1;
  15128. if ($string[$pos - 1] !== '\\')
  15129. {
  15130. $depth++;
  15131. while ($depth && $position < $length)
  15132. {
  15133. $position += strcspn($string, '()', $position);
  15134. if ($string[$position - 1] === '\\')
  15135. {
  15136. $position++;
  15137. continue;
  15138. }
  15139. elseif (isset($string[$position]))
  15140. {
  15141. switch ($string[$position])
  15142. {
  15143. case '(':
  15144. $depth++;
  15145. break;
  15146. case ')':
  15147. $depth--;
  15148. break;
  15149. }
  15150. $position++;
  15151. }
  15152. else
  15153. {
  15154. break;
  15155. }
  15156. }
  15157. }
  15158. else
  15159. {
  15160. $output .= '(';
  15161. }
  15162. }
  15163. $output .= substr($string, $position);
  15164. return $output;
  15165. }
  15166. public static function parse_mime($mime)
  15167. {
  15168. if (($pos = strpos($mime, ';')) === false)
  15169. {
  15170. return trim($mime);
  15171. }
  15172. else
  15173. {
  15174. return trim(substr($mime, 0, $pos));
  15175. }
  15176. }
  15177. public static function atom_03_construct_type($attribs)
  15178. {
  15179. if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
  15180. {
  15181. $mode = SIMPLEPIE_CONSTRUCT_BASE64;
  15182. }
  15183. else
  15184. {
  15185. $mode = SIMPLEPIE_CONSTRUCT_NONE;
  15186. }
  15187. if (isset($attribs['']['type']))
  15188. {
  15189. switch (strtolower(trim($attribs['']['type'])))
  15190. {
  15191. case 'text':
  15192. case 'text/plain':
  15193. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  15194. case 'html':
  15195. case 'text/html':
  15196. return SIMPLEPIE_CONSTRUCT_HTML | $mode;
  15197. case 'xhtml':
  15198. case 'application/xhtml+xml':
  15199. return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
  15200. default:
  15201. return SIMPLEPIE_CONSTRUCT_NONE | $mode;
  15202. }
  15203. }
  15204. else
  15205. {
  15206. return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
  15207. }
  15208. }
  15209. public static function atom_10_construct_type($attribs)
  15210. {
  15211. if (isset($attribs['']['type']))
  15212. {
  15213. switch (strtolower(trim($attribs['']['type'])))
  15214. {
  15215. case 'text':
  15216. return SIMPLEPIE_CONSTRUCT_TEXT;
  15217. case 'html':
  15218. return SIMPLEPIE_CONSTRUCT_HTML;
  15219. case 'xhtml':
  15220. return SIMPLEPIE_CONSTRUCT_XHTML;
  15221. default:
  15222. return SIMPLEPIE_CONSTRUCT_NONE;
  15223. }
  15224. }
  15225. return SIMPLEPIE_CONSTRUCT_TEXT;
  15226. }
  15227. public static function atom_10_content_construct_type($attribs)
  15228. {
  15229. if (isset($attribs['']['type']))
  15230. {
  15231. $type = strtolower(trim($attribs['']['type']));
  15232. switch ($type)
  15233. {
  15234. case 'text':
  15235. return SIMPLEPIE_CONSTRUCT_TEXT;
  15236. case 'html':
  15237. return SIMPLEPIE_CONSTRUCT_HTML;
  15238. case 'xhtml':
  15239. return SIMPLEPIE_CONSTRUCT_XHTML;
  15240. }
  15241. if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
  15242. {
  15243. return SIMPLEPIE_CONSTRUCT_NONE;
  15244. }
  15245. else
  15246. {
  15247. return SIMPLEPIE_CONSTRUCT_BASE64;
  15248. }
  15249. }
  15250. else
  15251. {
  15252. return SIMPLEPIE_CONSTRUCT_TEXT;
  15253. }
  15254. }
  15255. public static function is_isegment_nz_nc($string)
  15256. {
  15257. 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);
  15258. }
  15259. public static function space_seperated_tokens($string)
  15260. {
  15261. $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
  15262. $string_length = strlen($string);
  15263. $position = strspn($string, $space_characters);
  15264. $tokens = array();
  15265. while ($position < $string_length)
  15266. {
  15267. $len = strcspn($string, $space_characters, $position);
  15268. $tokens[] = substr($string, $position, $len);
  15269. $position += $len;
  15270. $position += strspn($string, $space_characters, $position);
  15271. }
  15272. return $tokens;
  15273. }
  15274. /**
  15275. * Converts a unicode codepoint to a UTF-8 character
  15276. *
  15277. * @static
  15278. * @param int $codepoint Unicode codepoint
  15279. * @return string UTF-8 character
  15280. */
  15281. public static function codepoint_to_utf8($codepoint)
  15282. {
  15283. $codepoint = (int) $codepoint;
  15284. if ($codepoint < 0)
  15285. {
  15286. return false;
  15287. }
  15288. else if ($codepoint <= 0x7f)
  15289. {
  15290. return chr($codepoint);
  15291. }
  15292. else if ($codepoint <= 0x7ff)
  15293. {
  15294. return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
  15295. }
  15296. else if ($codepoint <= 0xffff)
  15297. {
  15298. return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  15299. }
  15300. else if ($codepoint <= 0x10ffff)
  15301. {
  15302. return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
  15303. }
  15304. else
  15305. {
  15306. // U+FFFD REPLACEMENT CHARACTER
  15307. return "\xEF\xBF\xBD";
  15308. }
  15309. }
  15310. /**
  15311. * Similar to parse_str()
  15312. *
  15313. * Returns an associative array of name/value pairs, where the value is an
  15314. * array of values that have used the same name
  15315. *
  15316. * @static
  15317. * @param string $str The input string.
  15318. * @return array
  15319. */
  15320. public static function parse_str($str)
  15321. {
  15322. $return = array();
  15323. $str = explode('&', $str);
  15324. foreach ($str as $section)
  15325. {
  15326. if (strpos($section, '=') !== false)
  15327. {
  15328. list($name, $value) = explode('=', $section, 2);
  15329. $return[urldecode($name)][] = urldecode($value);
  15330. }
  15331. else
  15332. {
  15333. $return[urldecode($section)][] = null;
  15334. }
  15335. }
  15336. return $return;
  15337. }
  15338. /**
  15339. * Detect XML encoding, as per XML 1.0 Appendix F.1
  15340. *
  15341. * @todo Add support for EBCDIC
  15342. * @param string $data XML data
  15343. * @param SimplePie_Registry $registry Class registry
  15344. * @return array Possible encodings
  15345. */
  15346. public static function xml_encoding($data, $registry)
  15347. {
  15348. // UTF-32 Big Endian BOM
  15349. if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
  15350. {
  15351. $encoding[] = 'UTF-32BE';
  15352. }
  15353. // UTF-32 Little Endian BOM
  15354. elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
  15355. {
  15356. $encoding[] = 'UTF-32LE';
  15357. }
  15358. // UTF-16 Big Endian BOM
  15359. elseif (substr($data, 0, 2) === "\xFE\xFF")
  15360. {
  15361. $encoding[] = 'UTF-16BE';
  15362. }
  15363. // UTF-16 Little Endian BOM
  15364. elseif (substr($data, 0, 2) === "\xFF\xFE")
  15365. {
  15366. $encoding[] = 'UTF-16LE';
  15367. }
  15368. // UTF-8 BOM
  15369. elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
  15370. {
  15371. $encoding[] = 'UTF-8';
  15372. }
  15373. // UTF-32 Big Endian Without BOM
  15374. 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")
  15375. {
  15376. if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
  15377. {
  15378. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
  15379. if ($parser->parse())
  15380. {
  15381. $encoding[] = $parser->encoding;
  15382. }
  15383. }
  15384. $encoding[] = 'UTF-32BE';
  15385. }
  15386. // UTF-32 Little Endian Without BOM
  15387. 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")
  15388. {
  15389. if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
  15390. {
  15391. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
  15392. if ($parser->parse())
  15393. {
  15394. $encoding[] = $parser->encoding;
  15395. }
  15396. }
  15397. $encoding[] = 'UTF-32LE';
  15398. }
  15399. // UTF-16 Big Endian Without BOM
  15400. elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
  15401. {
  15402. if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
  15403. {
  15404. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
  15405. if ($parser->parse())
  15406. {
  15407. $encoding[] = $parser->encoding;
  15408. }
  15409. }
  15410. $encoding[] = 'UTF-16BE';
  15411. }
  15412. // UTF-16 Little Endian Without BOM
  15413. elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
  15414. {
  15415. if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
  15416. {
  15417. $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
  15418. if ($parser->parse())
  15419. {
  15420. $encoding[] = $parser->encoding;
  15421. }
  15422. }
  15423. $encoding[] = 'UTF-16LE';
  15424. }
  15425. // US-ASCII (or superset)
  15426. elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
  15427. {
  15428. if ($pos = strpos($data, "\x3F\x3E"))
  15429. {
  15430. $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
  15431. if ($parser->parse())
  15432. {
  15433. $encoding[] = $parser->encoding;
  15434. }
  15435. }
  15436. $encoding[] = 'UTF-8';
  15437. }
  15438. // Fallback to UTF-8
  15439. else
  15440. {
  15441. $encoding[] = 'UTF-8';
  15442. }
  15443. return $encoding;
  15444. }
  15445. public static function output_javascript()
  15446. {
  15447. if (function_exists('ob_gzhandler'))
  15448. {
  15449. ob_start('ob_gzhandler');
  15450. }
  15451. header('Content-type: text/javascript; charset: UTF-8');
  15452. header('Cache-Control: must-revalidate');
  15453. header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
  15454. ?>
  15455. function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
  15456. if (placeholder != '') {
  15457. 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>');
  15458. }
  15459. else {
  15460. 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>');
  15461. }
  15462. }
  15463. function embed_flash(bgcolor, width, height, link, loop, type) {
  15464. 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>');
  15465. }
  15466. function embed_flv(width, height, link, placeholder, loop, player) {
  15467. 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>');
  15468. }
  15469. function embed_wmedia(width, height, link) {
  15470. document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
  15471. }
  15472. <?php
  15473. }
  15474. /**
  15475. * Get the SimplePie build timestamp
  15476. *
  15477. * Uses the git index if it exists, otherwise uses the modification time
  15478. * of the newest file.
  15479. */
  15480. public static function get_build()
  15481. {
  15482. $root = dirname(dirname(__FILE__));
  15483. if (file_exists($root . '/.git/index'))
  15484. {
  15485. return filemtime($root . '/.git/index');
  15486. }
  15487. elseif (file_exists($root . '/SimplePie'))
  15488. {
  15489. $time = 0;
  15490. foreach (glob($root . '/SimplePie/*.php') as $file)
  15491. {
  15492. if (($mtime = filemtime($file)) > $time)
  15493. {
  15494. $time = $mtime;
  15495. }
  15496. }
  15497. return $time;
  15498. }
  15499. elseif (file_exists(dirname(__FILE__) . '/Core.php'))
  15500. {
  15501. return filemtime(dirname(__FILE__) . '/Core.php');
  15502. }
  15503. else
  15504. {
  15505. return filemtime(__FILE__);
  15506. }
  15507. }
  15508. /**
  15509. * Format debugging information
  15510. */
  15511. public static function debug(&$sp)
  15512. {
  15513. $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
  15514. $info .= 'PHP ' . PHP_VERSION . "\n";
  15515. if ($sp->error() !== null)
  15516. {
  15517. $info .= 'Error occurred: ' . $sp->error() . "\n";
  15518. }
  15519. else
  15520. {
  15521. $info .= "No error found.\n";
  15522. }
  15523. $info .= "Extensions:\n";
  15524. $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
  15525. foreach ($extensions as $ext)
  15526. {
  15527. if (extension_loaded($ext))
  15528. {
  15529. $info .= " $ext loaded\n";
  15530. switch ($ext)
  15531. {
  15532. case 'pcre':
  15533. $info .= ' Version ' . PCRE_VERSION . "\n";
  15534. break;
  15535. case 'curl':
  15536. $version = curl_version();
  15537. $info .= ' Version ' . $version['version'] . "\n";
  15538. break;
  15539. case 'mbstring':
  15540. $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
  15541. break;
  15542. case 'iconv':
  15543. $info .= ' Version ' . ICONV_VERSION . "\n";
  15544. break;
  15545. case 'xml':
  15546. $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
  15547. break;
  15548. }
  15549. }
  15550. else
  15551. {
  15552. $info .= " $ext not loaded\n";
  15553. }
  15554. }
  15555. return $info;
  15556. }
  15557. public static function silence_errors($num, $str)
  15558. {
  15559. // No-op
  15560. }
  15561. }
  15562. /**
  15563. * Parses XML into something sane
  15564. *
  15565. *
  15566. * This class can be overloaded with {@see SimplePie::set_parser_class()}
  15567. *
  15568. * @package SimplePie
  15569. * @subpackage Parsing
  15570. */
  15571. class SimplePie_Parser
  15572. {
  15573. var $error_code;
  15574. var $error_string;
  15575. var $current_line;
  15576. var $current_column;
  15577. var $current_byte;
  15578. var $separator = ' ';
  15579. var $namespace = array('');
  15580. var $element = array('');
  15581. var $xml_base = array('');
  15582. var $xml_base_explicit = array(false);
  15583. var $xml_lang = array('');
  15584. var $data = array();
  15585. var $datas = array(array());
  15586. var $current_xhtml_construct = -1;
  15587. var $encoding;
  15588. protected $registry;
  15589. public function set_registry(SimplePie_Registry $registry)
  15590. {
  15591. $this->registry = $registry;
  15592. }
  15593. public function parse(&$data, $encoding)
  15594. {
  15595. // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
  15596. if (strtoupper($encoding) === 'US-ASCII')
  15597. {
  15598. $this->encoding = 'UTF-8';
  15599. }
  15600. else
  15601. {
  15602. $this->encoding = $encoding;
  15603. }
  15604. // Strip BOM:
  15605. // UTF-32 Big Endian BOM
  15606. if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
  15607. {
  15608. $data = substr($data, 4);
  15609. }
  15610. // UTF-32 Little Endian BOM
  15611. elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
  15612. {
  15613. $data = substr($data, 4);
  15614. }
  15615. // UTF-16 Big Endian BOM
  15616. elseif (substr($data, 0, 2) === "\xFE\xFF")
  15617. {
  15618. $data = substr($data, 2);
  15619. }
  15620. // UTF-16 Little Endian BOM
  15621. elseif (substr($data, 0, 2) === "\xFF\xFE")
  15622. {
  15623. $data = substr($data, 2);
  15624. }
  15625. // UTF-8 BOM
  15626. elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
  15627. {
  15628. $data = substr($data, 3);
  15629. }
  15630. if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
  15631. {
  15632. $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
  15633. if ($declaration->parse())
  15634. {
  15635. $data = substr($data, $pos + 2);
  15636. $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
  15637. }
  15638. else
  15639. {
  15640. $this->error_string = 'SimplePie bug! Please report this!';
  15641. return false;
  15642. }
  15643. }
  15644. $return = true;
  15645. static $xml_is_sane = null;
  15646. if ($xml_is_sane === null)
  15647. {
  15648. $parser_check = xml_parser_create();
  15649. xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
  15650. xml_parser_free($parser_check);
  15651. $xml_is_sane = isset($values[0]['value']);
  15652. }
  15653. // Create the parser
  15654. if ($xml_is_sane)
  15655. {
  15656. $xml = xml_parser_create_ns($this->encoding, $this->separator);
  15657. xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
  15658. xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
  15659. xml_set_object($xml, $this);
  15660. xml_set_character_data_handler($xml, 'cdata');
  15661. xml_set_element_handler($xml, 'tag_open', 'tag_close');
  15662. // Parse!
  15663. if (!xml_parse($xml, $data, true))
  15664. {
  15665. $this->error_code = xml_get_error_code($xml);
  15666. $this->error_string = xml_error_string($this->error_code);
  15667. $return = false;
  15668. }
  15669. $this->current_line = xml_get_current_line_number($xml);
  15670. $this->current_column = xml_get_current_column_number($xml);
  15671. $this->current_byte = xml_get_current_byte_index($xml);
  15672. xml_parser_free($xml);
  15673. return $return;
  15674. }
  15675. else
  15676. {
  15677. libxml_clear_errors();
  15678. $xml = new XMLReader();
  15679. $xml->xml($data);
  15680. while (@$xml->read())
  15681. {
  15682. switch ($xml->nodeType)
  15683. {
  15684. case constant('XMLReader::END_ELEMENT'):
  15685. if ($xml->namespaceURI !== '')
  15686. {
  15687. $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
  15688. }
  15689. else
  15690. {
  15691. $tagName = $xml->localName;
  15692. }
  15693. $this->tag_close(null, $tagName);
  15694. break;
  15695. case constant('XMLReader::ELEMENT'):
  15696. $empty = $xml->isEmptyElement;
  15697. if ($xml->namespaceURI !== '')
  15698. {
  15699. $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
  15700. }
  15701. else
  15702. {
  15703. $tagName = $xml->localName;
  15704. }
  15705. $attributes = array();
  15706. while ($xml->moveToNextAttribute())
  15707. {
  15708. if ($xml->namespaceURI !== '')
  15709. {
  15710. $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
  15711. }
  15712. else
  15713. {
  15714. $attrName = $xml->localName;
  15715. }
  15716. $attributes[$attrName] = $xml->value;
  15717. }
  15718. $this->tag_open(null, $tagName, $attributes);
  15719. if ($empty)
  15720. {
  15721. $this->tag_close(null, $tagName);
  15722. }
  15723. break;
  15724. case constant('XMLReader::TEXT'):
  15725. case constant('XMLReader::CDATA'):
  15726. $this->cdata(null, $xml->value);
  15727. break;
  15728. }
  15729. }
  15730. if ($error = libxml_get_last_error())
  15731. {
  15732. $this->error_code = $error->code;
  15733. $this->error_string = $error->message;
  15734. $this->current_line = $error->line;
  15735. $this->current_column = $error->column;
  15736. return false;
  15737. }
  15738. else
  15739. {
  15740. return true;
  15741. }
  15742. }
  15743. }
  15744. public function get_error_code()
  15745. {
  15746. return $this->error_code;
  15747. }
  15748. public function get_error_string()
  15749. {
  15750. return $this->error_string;
  15751. }
  15752. public function get_current_line()
  15753. {
  15754. return $this->current_line;
  15755. }
  15756. public function get_current_column()
  15757. {
  15758. return $this->current_column;
  15759. }
  15760. public function get_current_byte()
  15761. {
  15762. return $this->current_byte;
  15763. }
  15764. public function get_data()
  15765. {
  15766. return $this->data;
  15767. }
  15768. public function tag_open($parser, $tag, $attributes)
  15769. {
  15770. list($this->namespace[], $this->element[]) = $this->split_ns($tag);
  15771. $attribs = array();
  15772. foreach ($attributes as $name => $value)
  15773. {
  15774. list($attrib_namespace, $attribute) = $this->split_ns($name);
  15775. $attribs[$attrib_namespace][$attribute] = $value;
  15776. }
  15777. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
  15778. {
  15779. $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
  15780. if ($base !== false)
  15781. {
  15782. $this->xml_base[] = $base;
  15783. $this->xml_base_explicit[] = true;
  15784. }
  15785. }
  15786. else
  15787. {
  15788. $this->xml_base[] = end($this->xml_base);
  15789. $this->xml_base_explicit[] = end($this->xml_base_explicit);
  15790. }
  15791. if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
  15792. {
  15793. $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
  15794. }
  15795. else
  15796. {
  15797. $this->xml_lang[] = end($this->xml_lang);
  15798. }
  15799. if ($this->current_xhtml_construct >= 0)
  15800. {
  15801. $this->current_xhtml_construct++;
  15802. if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
  15803. {
  15804. $this->data['data'] .= '<' . end($this->element);
  15805. if (isset($attribs['']))
  15806. {
  15807. foreach ($attribs[''] as $name => $value)
  15808. {
  15809. $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
  15810. }
  15811. }
  15812. $this->data['data'] .= '>';
  15813. }
  15814. }
  15815. else
  15816. {
  15817. $this->datas[] =& $this->data;
  15818. $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
  15819. $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));
  15820. 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')
  15821. || (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')
  15822. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
  15823. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
  15824. || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
  15825. {
  15826. $this->current_xhtml_construct = 0;
  15827. }
  15828. }
  15829. }
  15830. public function cdata($parser, $cdata)
  15831. {
  15832. if ($this->current_xhtml_construct >= 0)
  15833. {
  15834. $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
  15835. }
  15836. else
  15837. {
  15838. $this->data['data'] .= $cdata;
  15839. }
  15840. }
  15841. public function tag_close($parser, $tag)
  15842. {
  15843. if ($this->current_xhtml_construct >= 0)
  15844. {
  15845. $this->current_xhtml_construct--;
  15846. 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')))
  15847. {
  15848. $this->data['data'] .= '</' . end($this->element) . '>';
  15849. }
  15850. }
  15851. if ($this->current_xhtml_construct === -1)
  15852. {
  15853. $this->data =& $this->datas[count($this->datas) - 1];
  15854. array_pop($this->datas);
  15855. }
  15856. array_pop($this->element);
  15857. array_pop($this->namespace);
  15858. array_pop($this->xml_base);
  15859. array_pop($this->xml_base_explicit);
  15860. array_pop($this->xml_lang);
  15861. }
  15862. public function split_ns($string)
  15863. {
  15864. static $cache = array();
  15865. if (!isset($cache[$string]))
  15866. {
  15867. if ($pos = strpos($string, $this->separator))
  15868. {
  15869. static $separator_length;
  15870. if (!$separator_length)
  15871. {
  15872. $separator_length = strlen($this->separator);
  15873. }
  15874. $namespace = substr($string, 0, $pos);
  15875. $local_name = substr($string, $pos + $separator_length);
  15876. if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
  15877. {
  15878. $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
  15879. }
  15880. // Normalize the Media RSS namespaces
  15881. if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
  15882. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
  15883. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
  15884. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
  15885. $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
  15886. {
  15887. $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
  15888. }
  15889. $cache[$string] = array($namespace, $local_name);
  15890. }
  15891. else
  15892. {
  15893. $cache[$string] = array('', $string);
  15894. }
  15895. }
  15896. return $cache[$string];
  15897. }
  15898. }
  15899. /**
  15900. * Decode HTML Entities
  15901. *
  15902. * This implements HTML5 as of revision 967 (2007-06-28)
  15903. *
  15904. * @deprecated Use DOMDocument instead!
  15905. * @package SimplePie
  15906. */
  15907. class SimplePie_Decode_HTML_Entities
  15908. {
  15909. /**
  15910. * Data to be parsed
  15911. *
  15912. * @access private
  15913. * @var string
  15914. */
  15915. var $data = '';
  15916. /**
  15917. * Currently consumed bytes
  15918. *
  15919. * @access private
  15920. * @var string
  15921. */
  15922. var $consumed = '';
  15923. /**
  15924. * Position of the current byte being parsed
  15925. *
  15926. * @access private
  15927. * @var int
  15928. */
  15929. var $position = 0;
  15930. /**
  15931. * Create an instance of the class with the input data
  15932. *
  15933. * @access public
  15934. * @param string $data Input data
  15935. */
  15936. public function __construct($data)
  15937. {
  15938. $this->data = $data;
  15939. }
  15940. /**
  15941. * Parse the input data
  15942. *
  15943. * @access public
  15944. * @return string Output data
  15945. */
  15946. public function parse()
  15947. {
  15948. while (($this->position = strpos($this->data, '&', $this->position)) !== false)
  15949. {
  15950. $this->consume();
  15951. $this->entity();
  15952. $this->consumed = '';
  15953. }
  15954. return $this->data;
  15955. }
  15956. /**
  15957. * Consume the next byte
  15958. *
  15959. * @access private
  15960. * @return mixed The next byte, or false, if there is no more data
  15961. */
  15962. public function consume()
  15963. {
  15964. if (isset($this->data[$this->position]))
  15965. {
  15966. $this->consumed .= $this->data[$this->position];
  15967. return $this->data[$this->position++];
  15968. }
  15969. else
  15970. {
  15971. return false;
  15972. }
  15973. }
  15974. /**
  15975. * Consume a range of characters
  15976. *
  15977. * @access private
  15978. * @param string $chars Characters to consume
  15979. * @return mixed A series of characters that match the range, or false
  15980. */
  15981. public function consume_range($chars)
  15982. {
  15983. if ($len = strspn($this->data, $chars, $this->position))
  15984. {
  15985. $data = substr($this->data, $this->position, $len);
  15986. $this->consumed .= $data;
  15987. $this->position += $len;
  15988. return $data;
  15989. }
  15990. else
  15991. {
  15992. return false;
  15993. }
  15994. }
  15995. /**
  15996. * Unconsume one byte
  15997. *
  15998. * @access private
  15999. */
  16000. public function unconsume()
  16001. {
  16002. $this->consumed = substr($this->consumed, 0, -1);
  16003. $this->position--;
  16004. }
  16005. /**
  16006. * Decode an entity
  16007. *
  16008. * @access private
  16009. */
  16010. public function entity()
  16011. {
  16012. switch ($this->consume())
  16013. {
  16014. case "\x09":
  16015. case "\x0A":
  16016. case "\x0B":
  16017. case "\x0B":
  16018. case "\x0C":
  16019. case "\x20":
  16020. case "\x3C":
  16021. case "\x26":
  16022. case false:
  16023. break;
  16024. case "\x23":
  16025. switch ($this->consume())
  16026. {
  16027. case "\x78":
  16028. case "\x58":
  16029. $range = '0123456789ABCDEFabcdef';
  16030. $hex = true;
  16031. break;
  16032. default:
  16033. $range = '0123456789';
  16034. $hex = false;
  16035. $this->unconsume();
  16036. break;
  16037. }
  16038. if ($codepoint = $this->consume_range($range))
  16039. {
  16040. 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");
  16041. if ($hex)
  16042. {
  16043. $codepoint = hexdec($codepoint);
  16044. }
  16045. else
  16046. {
  16047. $codepoint = intval($codepoint);
  16048. }
  16049. if (isset($windows_1252_specials[$codepoint]))
  16050. {
  16051. $replacement = $windows_1252_specials[$codepoint];
  16052. }
  16053. else
  16054. {
  16055. $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
  16056. }
  16057. if (!in_array($this->consume(), array(';', false), true))
  16058. {
  16059. $this->unconsume();
  16060. }
  16061. $consumed_length = strlen($this->consumed);
  16062. $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
  16063. $this->position += strlen($replacement) - $consumed_length;
  16064. }
  16065. break;
  16066. default:
  16067. static $entities = array(
  16068. 'Aacute' => "\xC3\x81",
  16069. 'aacute' => "\xC3\xA1",
  16070. 'Aacute;' => "\xC3\x81",
  16071. 'aacute;' => "\xC3\xA1",
  16072. 'Acirc' => "\xC3\x82",
  16073. 'acirc' => "\xC3\xA2",
  16074. 'Acirc;' => "\xC3\x82",
  16075. 'acirc;' => "\xC3\xA2",
  16076. 'acute' => "\xC2\xB4",
  16077. 'acute;' => "\xC2\xB4",
  16078. 'AElig' => "\xC3\x86",
  16079. 'aelig' => "\xC3\xA6",
  16080. 'AElig;' => "\xC3\x86",
  16081. 'aelig;' => "\xC3\xA6",
  16082. 'Agrave' => "\xC3\x80",
  16083. 'agrave' => "\xC3\xA0",
  16084. 'Agrave;' => "\xC3\x80",
  16085. 'agrave;' => "\xC3\xA0",
  16086. 'alefsym;' => "\xE2\x84\xB5",
  16087. 'Alpha;' => "\xCE\x91",
  16088. 'alpha;' => "\xCE\xB1",
  16089. 'AMP' => "\x26",
  16090. 'amp' => "\x26",
  16091. 'AMP;' => "\x26",
  16092. 'amp;' => "\x26",
  16093. 'and;' => "\xE2\x88\xA7",
  16094. 'ang;' => "\xE2\x88\xA0",
  16095. 'apos;' => "\x27",
  16096. 'Aring' => "\xC3\x85",
  16097. 'aring' => "\xC3\xA5",
  16098. 'Aring;' => "\xC3\x85",
  16099. 'aring;' => "\xC3\xA5",
  16100. 'asymp;' => "\xE2\x89\x88",
  16101. 'Atilde' => "\xC3\x83",
  16102. 'atilde' => "\xC3\xA3",
  16103. 'Atilde;' => "\xC3\x83",
  16104. 'atilde;' => "\xC3\xA3",
  16105. 'Auml' => "\xC3\x84",
  16106. 'auml' => "\xC3\xA4",
  16107. 'Auml;' => "\xC3\x84",
  16108. 'auml;' => "\xC3\xA4",
  16109. 'bdquo;' => "\xE2\x80\x9E",
  16110. 'Beta;' => "\xCE\x92",
  16111. 'beta;' => "\xCE\xB2",
  16112. 'brvbar' => "\xC2\xA6",
  16113. 'brvbar;' => "\xC2\xA6",
  16114. 'bull;' => "\xE2\x80\xA2",
  16115. 'cap;' => "\xE2\x88\xA9",
  16116. 'Ccedil' => "\xC3\x87",
  16117. 'ccedil' => "\xC3\xA7",
  16118. 'Ccedil;' => "\xC3\x87",
  16119. 'ccedil;' => "\xC3\xA7",
  16120. 'cedil' => "\xC2\xB8",
  16121. 'cedil;' => "\xC2\xB8",
  16122. 'cent' => "\xC2\xA2",
  16123. 'cent;' => "\xC2\xA2",
  16124. 'Chi;' => "\xCE\xA7",
  16125. 'chi;' => "\xCF\x87",
  16126. 'circ;' => "\xCB\x86",
  16127. 'clubs;' => "\xE2\x99\xA3",
  16128. 'cong;' => "\xE2\x89\x85",
  16129. 'COPY' => "\xC2\xA9",
  16130. 'copy' => "\xC2\xA9",
  16131. 'COPY;' => "\xC2\xA9",
  16132. 'copy;' => "\xC2\xA9",
  16133. 'crarr;' => "\xE2\x86\xB5",
  16134. 'cup;' => "\xE2\x88\xAA",
  16135. 'curren' => "\xC2\xA4",
  16136. 'curren;' => "\xC2\xA4",
  16137. 'Dagger;' => "\xE2\x80\xA1",
  16138. 'dagger;' => "\xE2\x80\xA0",
  16139. 'dArr;' => "\xE2\x87\x93",
  16140. 'darr;' => "\xE2\x86\x93",
  16141. 'deg' => "\xC2\xB0",
  16142. 'deg;' => "\xC2\xB0",
  16143. 'Delta;' => "\xCE\x94",
  16144. 'delta;' => "\xCE\xB4",
  16145. 'diams;' => "\xE2\x99\xA6",
  16146. 'divide' => "\xC3\xB7",
  16147. 'divide;' => "\xC3\xB7",
  16148. 'Eacute' => "\xC3\x89",
  16149. 'eacute' => "\xC3\xA9",
  16150. 'Eacute;' => "\xC3\x89",
  16151. 'eacute;' => "\xC3\xA9",
  16152. 'Ecirc' => "\xC3\x8A",
  16153. 'ecirc' => "\xC3\xAA",
  16154. 'Ecirc;' => "\xC3\x8A",
  16155. 'ecirc;' => "\xC3\xAA",
  16156. 'Egrave' => "\xC3\x88",
  16157. 'egrave' => "\xC3\xA8",
  16158. 'Egrave;' => "\xC3\x88",
  16159. 'egrave;' => "\xC3\xA8",
  16160. 'empty;' => "\xE2\x88\x85",
  16161. 'emsp;' => "\xE2\x80\x83",
  16162. 'ensp;' => "\xE2\x80\x82",
  16163. 'Epsilon;' => "\xCE\x95",
  16164. 'epsilon;' => "\xCE\xB5",
  16165. 'equiv;' => "\xE2\x89\xA1",
  16166. 'Eta;' => "\xCE\x97",
  16167. 'eta;' => "\xCE\xB7",
  16168. 'ETH' => "\xC3\x90",
  16169. 'eth' => "\xC3\xB0",
  16170. 'ETH;' => "\xC3\x90",
  16171. 'eth;' => "\xC3\xB0",
  16172. 'Euml' => "\xC3\x8B",
  16173. 'euml' => "\xC3\xAB",
  16174. 'Euml;' => "\xC3\x8B",
  16175. 'euml;' => "\xC3\xAB",
  16176. 'euro;' => "\xE2\x82\xAC",
  16177. 'exist;' => "\xE2\x88\x83",
  16178. 'fnof;' => "\xC6\x92",
  16179. 'forall;' => "\xE2\x88\x80",
  16180. 'frac12' => "\xC2\xBD",
  16181. 'frac12;' => "\xC2\xBD",
  16182. 'frac14' => "\xC2\xBC",
  16183. 'frac14;' => "\xC2\xBC",
  16184. 'frac34' => "\xC2\xBE",
  16185. 'frac34;' => "\xC2\xBE",
  16186. 'frasl;' => "\xE2\x81\x84",
  16187. 'Gamma;' => "\xCE\x93",
  16188. 'gamma;' => "\xCE\xB3",
  16189. 'ge;' => "\xE2\x89\xA5",
  16190. 'GT' => "\x3E",
  16191. 'gt' => "\x3E",
  16192. 'GT;' => "\x3E",
  16193. 'gt;' => "\x3E",
  16194. 'hArr;' => "\xE2\x87\x94",
  16195. 'harr;' => "\xE2\x86\x94",
  16196. 'hearts;' => "\xE2\x99\xA5",
  16197. 'hellip;' => "\xE2\x80\xA6",
  16198. 'Iacute' => "\xC3\x8D",
  16199. 'iacute' => "\xC3\xAD",
  16200. 'Iacute;' => "\xC3\x8D",
  16201. 'iacute;' => "\xC3\xAD",
  16202. 'Icirc' => "\xC3\x8E",
  16203. 'icirc' => "\xC3\xAE",
  16204. 'Icirc;' => "\xC3\x8E",
  16205. 'icirc;' => "\xC3\xAE",
  16206. 'iexcl' => "\xC2\xA1",
  16207. 'iexcl;' => "\xC2\xA1",
  16208. 'Igrave' => "\xC3\x8C",
  16209. 'igrave' => "\xC3\xAC",
  16210. 'Igrave;' => "\xC3\x8C",
  16211. 'igrave;' => "\xC3\xAC",
  16212. 'image;' => "\xE2\x84\x91",
  16213. 'infin;' => "\xE2\x88\x9E",
  16214. 'int;' => "\xE2\x88\xAB",
  16215. 'Iota;' => "\xCE\x99",
  16216. 'iota;' => "\xCE\xB9",
  16217. 'iquest' => "\xC2\xBF",
  16218. 'iquest;' => "\xC2\xBF",
  16219. 'isin;' => "\xE2\x88\x88",
  16220. 'Iuml' => "\xC3\x8F",
  16221. 'iuml' => "\xC3\xAF",
  16222. 'Iuml;' => "\xC3\x8F",
  16223. 'iuml;' => "\xC3\xAF",
  16224. 'Kappa;' => "\xCE\x9A",
  16225. 'kappa;' => "\xCE\xBA",
  16226. 'Lambda;' => "\xCE\x9B",
  16227. 'lambda;' => "\xCE\xBB",
  16228. 'lang;' => "\xE3\x80\x88",
  16229. 'laquo' => "\xC2\xAB",
  16230. 'laquo;' => "\xC2\xAB",
  16231. 'lArr;' => "\xE2\x87\x90",
  16232. 'larr;' => "\xE2\x86\x90",
  16233. 'lceil;' => "\xE2\x8C\x88",
  16234. 'ldquo;' => "\xE2\x80\x9C",
  16235. 'le;' => "\xE2\x89\xA4",
  16236. 'lfloor;' => "\xE2\x8C\x8A",
  16237. 'lowast;' => "\xE2\x88\x97",
  16238. 'loz;' => "\xE2\x97\x8A",
  16239. 'lrm;' => "\xE2\x80\x8E",
  16240. 'lsaquo;' => "\xE2\x80\xB9",
  16241. 'lsquo;' => "\xE2\x80\x98",
  16242. 'LT' => "\x3C",
  16243. 'lt' => "\x3C",
  16244. 'LT;' => "\x3C",
  16245. 'lt;' => "\x3C",
  16246. 'macr' => "\xC2\xAF",
  16247. 'macr;' => "\xC2\xAF",
  16248. 'mdash;' => "\xE2\x80\x94",
  16249. 'micro' => "\xC2\xB5",
  16250. 'micro;' => "\xC2\xB5",
  16251. 'middot' => "\xC2\xB7",
  16252. 'middot;' => "\xC2\xB7",
  16253. 'minus;' => "\xE2\x88\x92",
  16254. 'Mu;' => "\xCE\x9C",
  16255. 'mu;' => "\xCE\xBC",
  16256. 'nabla;' => "\xE2\x88\x87",
  16257. 'nbsp' => "\xC2\xA0",
  16258. 'nbsp;' => "\xC2\xA0",
  16259. 'ndash;' => "\xE2\x80\x93",
  16260. 'ne;' => "\xE2\x89\xA0",
  16261. 'ni;' => "\xE2\x88\x8B",
  16262. 'not' => "\xC2\xAC",
  16263. 'not;' => "\xC2\xAC",
  16264. 'notin;' => "\xE2\x88\x89",
  16265. 'nsub;' => "\xE2\x8A\x84",
  16266. 'Ntilde' => "\xC3\x91",
  16267. 'ntilde' => "\xC3\xB1",
  16268. 'Ntilde;' => "\xC3\x91",
  16269. 'ntilde;' => "\xC3\xB1",
  16270. 'Nu;' => "\xCE\x9D",
  16271. 'nu;' => "\xCE\xBD",
  16272. 'Oacute' => "\xC3\x93",
  16273. 'oacute' => "\xC3\xB3",
  16274. 'Oacute;' => "\xC3\x93",
  16275. 'oacute;' => "\xC3\xB3",
  16276. 'Ocirc' => "\xC3\x94",
  16277. 'ocirc' => "\xC3\xB4",
  16278. 'Ocirc;' => "\xC3\x94",
  16279. 'ocirc;' => "\xC3\xB4",
  16280. 'OElig;' => "\xC5\x92",
  16281. 'oelig;' => "\xC5\x93",
  16282. 'Ograve' => "\xC3\x92",
  16283. 'ograve' => "\xC3\xB2",
  16284. 'Ograve;' => "\xC3\x92",
  16285. 'ograve;' => "\xC3\xB2",
  16286. 'oline;' => "\xE2\x80\xBE",
  16287. 'Omega;' => "\xCE\xA9",
  16288. 'omega;' => "\xCF\x89",
  16289. 'Omicron;' => "\xCE\x9F",
  16290. 'omicron;' => "\xCE\xBF",
  16291. 'oplus;' => "\xE2\x8A\x95",
  16292. 'or;' => "\xE2\x88\xA8",
  16293. 'ordf' => "\xC2\xAA",
  16294. 'ordf;' => "\xC2\xAA",
  16295. 'ordm' => "\xC2\xBA",
  16296. 'ordm;' => "\xC2\xBA",
  16297. 'Oslash' => "\xC3\x98",
  16298. 'oslash' => "\xC3\xB8",
  16299. 'Oslash;' => "\xC3\x98",
  16300. 'oslash;' => "\xC3\xB8",
  16301. 'Otilde' => "\xC3\x95",
  16302. 'otilde' => "\xC3\xB5",
  16303. 'Otilde;' => "\xC3\x95",
  16304. 'otilde;' => "\xC3\xB5",
  16305. 'otimes;' => "\xE2\x8A\x97",
  16306. 'Ouml' => "\xC3\x96",
  16307. 'ouml' => "\xC3\xB6",
  16308. 'Ouml;' => "\xC3\x96",
  16309. 'ouml;' => "\xC3\xB6",
  16310. 'para' => "\xC2\xB6",
  16311. 'para;' => "\xC2\xB6",
  16312. 'part;' => "\xE2\x88\x82",
  16313. 'permil;' => "\xE2\x80\xB0",
  16314. 'perp;' => "\xE2\x8A\xA5",
  16315. 'Phi;' => "\xCE\xA6",
  16316. 'phi;' => "\xCF\x86",
  16317. 'Pi;' => "\xCE\xA0",
  16318. 'pi;' => "\xCF\x80",
  16319. 'piv;' => "\xCF\x96",
  16320. 'plusmn' => "\xC2\xB1",
  16321. 'plusmn;' => "\xC2\xB1",
  16322. 'pound' => "\xC2\xA3",
  16323. 'pound;' => "\xC2\xA3",
  16324. 'Prime;' => "\xE2\x80\xB3",
  16325. 'prime;' => "\xE2\x80\xB2",
  16326. 'prod;' => "\xE2\x88\x8F",
  16327. 'prop;' => "\xE2\x88\x9D",
  16328. 'Psi;' => "\xCE\xA8",
  16329. 'psi;' => "\xCF\x88",
  16330. 'QUOT' => "\x22",
  16331. 'quot' => "\x22",
  16332. 'QUOT;' => "\x22",
  16333. 'quot;' => "\x22",
  16334. 'radic;' => "\xE2\x88\x9A",
  16335. 'rang;' => "\xE3\x80\x89",
  16336. 'raquo' => "\xC2\xBB",
  16337. 'raquo;' => "\xC2\xBB",
  16338. 'rArr;' => "\xE2\x87\x92",
  16339. 'rarr;' => "\xE2\x86\x92",
  16340. 'rceil;' => "\xE2\x8C\x89",
  16341. 'rdquo;' => "\xE2\x80\x9D",
  16342. 'real;' => "\xE2\x84\x9C",
  16343. 'REG' => "\xC2\xAE",
  16344. 'reg' => "\xC2\xAE",
  16345. 'REG;' => "\xC2\xAE",
  16346. 'reg;' => "\xC2\xAE",
  16347. 'rfloor;' => "\xE2\x8C\x8B",
  16348. 'Rho;' => "\xCE\xA1",
  16349. 'rho;' => "\xCF\x81",
  16350. 'rlm;' => "\xE2\x80\x8F",
  16351. 'rsaquo;' => "\xE2\x80\xBA",
  16352. 'rsquo;' => "\xE2\x80\x99",
  16353. 'sbquo;' => "\xE2\x80\x9A",
  16354. 'Scaron;' => "\xC5\xA0",
  16355. 'scaron;' => "\xC5\xA1",
  16356. 'sdot;' => "\xE2\x8B\x85",
  16357. 'sect' => "\xC2\xA7",
  16358. 'sect;' => "\xC2\xA7",
  16359. 'shy' => "\xC2\xAD",
  16360. 'shy;' => "\xC2\xAD",
  16361. 'Sigma;' => "\xCE\xA3",
  16362. 'sigma;' => "\xCF\x83",
  16363. 'sigmaf;' => "\xCF\x82",
  16364. 'sim;' => "\xE2\x88\xBC",
  16365. 'spades;' => "\xE2\x99\xA0",
  16366. 'sub;' => "\xE2\x8A\x82",
  16367. 'sube;' => "\xE2\x8A\x86",
  16368. 'sum;' => "\xE2\x88\x91",
  16369. 'sup;' => "\xE2\x8A\x83",
  16370. 'sup1' => "\xC2\xB9",
  16371. 'sup1;' => "\xC2\xB9",
  16372. 'sup2' => "\xC2\xB2",
  16373. 'sup2;' => "\xC2\xB2",
  16374. 'sup3' => "\xC2\xB3",
  16375. 'sup3;' => "\xC2\xB3",
  16376. 'supe;' => "\xE2\x8A\x87",
  16377. 'szlig' => "\xC3\x9F",
  16378. 'szlig;' => "\xC3\x9F",
  16379. 'Tau;' => "\xCE\xA4",
  16380. 'tau;' => "\xCF\x84",
  16381. 'there4;' => "\xE2\x88\xB4",
  16382. 'Theta;' => "\xCE\x98",
  16383. 'theta;' => "\xCE\xB8",
  16384. 'thetasym;' => "\xCF\x91",
  16385. 'thinsp;' => "\xE2\x80\x89",
  16386. 'THORN' => "\xC3\x9E",
  16387. 'thorn' => "\xC3\xBE",
  16388. 'THORN;' => "\xC3\x9E",
  16389. 'thorn;' => "\xC3\xBE",
  16390. 'tilde;' => "\xCB\x9C",
  16391. 'times' => "\xC3\x97",
  16392. 'times;' => "\xC3\x97",
  16393. 'TRADE;' => "\xE2\x84\xA2",
  16394. 'trade;' => "\xE2\x84\xA2",
  16395. 'Uacute' => "\xC3\x9A",
  16396. 'uacute' => "\xC3\xBA",
  16397. 'Uacute;' => "\xC3\x9A",
  16398. 'uacute;' => "\xC3\xBA",
  16399. 'uArr;' => "\xE2\x87\x91",
  16400. 'uarr;' => "\xE2\x86\x91",
  16401. 'Ucirc' => "\xC3\x9B",
  16402. 'ucirc' => "\xC3\xBB",
  16403. 'Ucirc;' => "\xC3\x9B",
  16404. 'ucirc;' => "\xC3\xBB",
  16405. 'Ugrave' => "\xC3\x99",
  16406. 'ugrave' => "\xC3\xB9",
  16407. 'Ugrave;' => "\xC3\x99",
  16408. 'ugrave;' => "\xC3\xB9",
  16409. 'uml' => "\xC2\xA8",
  16410. 'uml;' => "\xC2\xA8",
  16411. 'upsih;' => "\xCF\x92",
  16412. 'Upsilon;' => "\xCE\xA5",
  16413. 'upsilon;' => "\xCF\x85",
  16414. 'Uuml' => "\xC3\x9C",
  16415. 'uuml' => "\xC3\xBC",
  16416. 'Uuml;' => "\xC3\x9C",
  16417. 'uuml;' => "\xC3\xBC",
  16418. 'weierp;' => "\xE2\x84\x98",
  16419. 'Xi;' => "\xCE\x9E",
  16420. 'xi;' => "\xCE\xBE",
  16421. 'Yacute' => "\xC3\x9D",
  16422. 'yacute' => "\xC3\xBD",
  16423. 'Yacute;' => "\xC3\x9D",
  16424. 'yacute;' => "\xC3\xBD",
  16425. 'yen' => "\xC2\xA5",
  16426. 'yen;' => "\xC2\xA5",
  16427. 'yuml' => "\xC3\xBF",
  16428. 'Yuml;' => "\xC5\xB8",
  16429. 'yuml;' => "\xC3\xBF",
  16430. 'Zeta;' => "\xCE\x96",
  16431. 'zeta;' => "\xCE\xB6",
  16432. 'zwj;' => "\xE2\x80\x8D",
  16433. 'zwnj;' => "\xE2\x80\x8C"
  16434. );
  16435. for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
  16436. {
  16437. $consumed = substr($this->consumed, 1);
  16438. if (isset($entities[$consumed]))
  16439. {
  16440. $match = $consumed;
  16441. }
  16442. }
  16443. if ($match !== null)
  16444. {
  16445. $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
  16446. $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
  16447. }
  16448. break;
  16449. }
  16450. }
  16451. }
  16452. ?>