Release 2015-08-10 "Detritus"
[dokuwiki.git] / inc / SimplePie.php
blob8a90605095b1fd0ecddac5078a61ea9cb0cc609c
1 <?php
2 /**
3 * SimplePie
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
8 * Please note: This file is automatically generated by a build script. The
9 * full original source is always available from http://simplepie.org/
11 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
12 * All rights reserved.
14 * Redistribution and use in source and binary forms, with or without modification, are
15 * permitted provided that the following conditions are met:
17 * * Redistributions of source code must retain the above copyright notice, this list of
18 * conditions and the following disclaimer.
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.
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.
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.
38 * @package SimplePie
39 * @version 1.3.1
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
48 /**
49 * SimplePie Name
51 define('SIMPLEPIE_NAME', 'SimplePie');
53 /**
54 * SimplePie Version
56 define('SIMPLEPIE_VERSION', '1.3.1');
58 /**
59 * SimplePie Build
60 * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
62 define('SIMPLEPIE_BUILD', '20121030175911');
64 /**
65 * SimplePie Website URL
67 define('SIMPLEPIE_URL', 'http://simplepie.org');
69 /**
70 * SimplePie Useragent
71 * @see SimplePie::set_useragent()
73 define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
75 /**
76 * SimplePie Linkback
78 define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
80 /**
81 * No Autodiscovery
82 * @see SimplePie::set_autodiscovery_level()
84 define('SIMPLEPIE_LOCATOR_NONE', 0);
86 /**
87 * Feed Link Element Autodiscovery
88 * @see SimplePie::set_autodiscovery_level()
90 define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
92 /**
93 * Local Feed Extension Autodiscovery
94 * @see SimplePie::set_autodiscovery_level()
96 define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
98 /**
99 * Local Feed Body Autodiscovery
100 * @see SimplePie::set_autodiscovery_level()
102 define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
105 * Remote Feed Extension Autodiscovery
106 * @see SimplePie::set_autodiscovery_level()
108 define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
111 * Remote Feed Body Autodiscovery
112 * @see SimplePie::set_autodiscovery_level()
114 define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
117 * All Feed Autodiscovery
118 * @see SimplePie::set_autodiscovery_level()
120 define('SIMPLEPIE_LOCATOR_ALL', 31);
123 * No known feed type
125 define('SIMPLEPIE_TYPE_NONE', 0);
128 * RSS 0.90
130 define('SIMPLEPIE_TYPE_RSS_090', 1);
133 * RSS 0.91 (Netscape)
135 define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
138 * RSS 0.91 (Userland)
140 define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
143 * RSS 0.91 (both Netscape and Userland)
145 define('SIMPLEPIE_TYPE_RSS_091', 6);
148 * RSS 0.92
150 define('SIMPLEPIE_TYPE_RSS_092', 8);
153 * RSS 0.93
155 define('SIMPLEPIE_TYPE_RSS_093', 16);
158 * RSS 0.94
160 define('SIMPLEPIE_TYPE_RSS_094', 32);
163 * RSS 1.0
165 define('SIMPLEPIE_TYPE_RSS_10', 64);
168 * RSS 2.0
170 define('SIMPLEPIE_TYPE_RSS_20', 128);
173 * RDF-based RSS
175 define('SIMPLEPIE_TYPE_RSS_RDF', 65);
178 * Non-RDF-based RSS (truly intended as syndication format)
180 define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
183 * All RSS
185 define('SIMPLEPIE_TYPE_RSS_ALL', 255);
188 * Atom 0.3
190 define('SIMPLEPIE_TYPE_ATOM_03', 256);
193 * Atom 1.0
195 define('SIMPLEPIE_TYPE_ATOM_10', 512);
198 * All Atom
200 define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
203 * All feed types
205 define('SIMPLEPIE_TYPE_ALL', 1023);
208 * No construct
210 define('SIMPLEPIE_CONSTRUCT_NONE', 0);
213 * Text construct
215 define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
218 * HTML construct
220 define('SIMPLEPIE_CONSTRUCT_HTML', 2);
223 * XHTML construct
225 define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
228 * base64-encoded construct
230 define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
233 * IRI construct
235 define('SIMPLEPIE_CONSTRUCT_IRI', 16);
238 * A construct that might be HTML
240 define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
243 * All constructs
245 define('SIMPLEPIE_CONSTRUCT_ALL', 63);
248 * Don't change case
250 define('SIMPLEPIE_SAME_CASE', 1);
253 * Change to lowercase
255 define('SIMPLEPIE_LOWERCASE', 2);
258 * Change to uppercase
260 define('SIMPLEPIE_UPPERCASE', 4);
263 * PCRE for HTML attributes
265 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]*');
268 * PCRE for XML attributes
270 define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
273 * XML Namespace
275 define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
278 * Atom 1.0 Namespace
280 define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
283 * Atom 0.3 Namespace
285 define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
288 * RDF Namespace
290 define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
293 * RSS 0.90 Namespace
295 define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
298 * RSS 1.0 Namespace
300 define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
303 * RSS 1.0 Content Module Namespace
305 define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
308 * RSS 2.0 Namespace
309 * (Stupid, I know, but I'm certain it will confuse people less with support.)
311 define('SIMPLEPIE_NAMESPACE_RSS_20', '');
314 * DC 1.0 Namespace
316 define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
319 * DC 1.1 Namespace
321 define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
324 * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
326 define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
329 * GeoRSS Namespace
331 define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
334 * Media RSS Namespace
336 define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
339 * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
341 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
344 * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
346 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
349 * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
351 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
354 * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
356 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
359 * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
361 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
364 * iTunes RSS Namespace
366 define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
369 * XHTML Namespace
371 define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
374 * IANA Link Relations Registry
376 define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
379 * No file source
381 define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
384 * Remote file source
386 define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
389 * Local file source
391 define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
394 * fsockopen() file source
396 define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
399 * cURL file source
401 define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
404 * file_get_contents() file source
406 define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
409 * SimplePie
411 * @package SimplePie
412 * @subpackage API
414 class SimplePie
417 * @var array Raw data
418 * @access private
420 public $data = array();
423 * @var mixed Error string
424 * @access private
426 public $error;
429 * @var object Instance of SimplePie_Sanitize (or other class)
430 * @see SimplePie::set_sanitize_class()
431 * @access private
433 public $sanitize;
436 * @var string SimplePie Useragent
437 * @see SimplePie::set_useragent()
438 * @access private
440 public $useragent = SIMPLEPIE_USERAGENT;
443 * @var string Feed URL
444 * @see SimplePie::set_feed_url()
445 * @access private
447 public $feed_url;
450 * @var object Instance of SimplePie_File to use as a feed
451 * @see SimplePie::set_file()
452 * @access private
454 public $file;
457 * @var string Raw feed data
458 * @see SimplePie::set_raw_data()
459 * @access private
461 public $raw_data;
464 * @var int Timeout for fetching remote files
465 * @see SimplePie::set_timeout()
466 * @access private
468 public $timeout = 10;
471 * @var bool Forces fsockopen() to be used for remote files instead
472 * of cURL, even if a new enough version is installed
473 * @see SimplePie::force_fsockopen()
474 * @access private
476 public $force_fsockopen = false;
479 * @var bool Force the given data/URL to be treated as a feed no matter what
480 * it appears like
481 * @see SimplePie::force_feed()
482 * @access private
484 public $force_feed = false;
487 * @var bool Enable/Disable Caching
488 * @see SimplePie::enable_cache()
489 * @access private
491 public $cache = true;
494 * @var int Cache duration (in seconds)
495 * @see SimplePie::set_cache_duration()
496 * @access private
498 public $cache_duration = 3600;
501 * @var int Auto-discovery cache duration (in seconds)
502 * @see SimplePie::set_autodiscovery_cache_duration()
503 * @access private
505 public $autodiscovery_cache_duration = 604800; // 7 Days.
508 * @var string Cache location (relative to executing script)
509 * @see SimplePie::set_cache_location()
510 * @access private
512 public $cache_location = './cache';
515 * @var string Function that creates the cache filename
516 * @see SimplePie::set_cache_name_function()
517 * @access private
519 public $cache_name_function = 'md5';
522 * @var bool Reorder feed by date descending
523 * @see SimplePie::enable_order_by_date()
524 * @access private
526 public $order_by_date = true;
529 * @var mixed Force input encoding to be set to the follow value
530 * (false, or anything type-cast to false, disables this feature)
531 * @see SimplePie::set_input_encoding()
532 * @access private
534 public $input_encoding = false;
537 * @var int Feed Autodiscovery Level
538 * @see SimplePie::set_autodiscovery_level()
539 * @access private
541 public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
544 * Class registry object
546 * @var SimplePie_Registry
548 public $registry;
551 * @var int Maximum number of feeds to check with autodiscovery
552 * @see SimplePie::set_max_checked_feeds()
553 * @access private
555 public $max_checked_feeds = 10;
558 * @var array All the feeds found during the autodiscovery process
559 * @see SimplePie::get_all_discovered_feeds()
560 * @access private
562 public $all_discovered_feeds = array();
565 * @var string Web-accessible path to the handler_image.php file.
566 * @see SimplePie::set_image_handler()
567 * @access private
569 public $image_handler = '';
572 * @var array Stores the URLs when multiple feeds are being initialized.
573 * @see SimplePie::set_feed_url()
574 * @access private
576 public $multifeed_url = array();
579 * @var array Stores SimplePie objects when multiple feeds initialized.
580 * @access private
582 public $multifeed_objects = array();
585 * @var array Stores the get_object_vars() array for use with multifeeds.
586 * @see SimplePie::set_feed_url()
587 * @access private
589 public $config_settings = null;
592 * @var integer Stores the number of items to return per-feed with multifeeds.
593 * @see SimplePie::set_item_limit()
594 * @access private
596 public $item_limit = 0;
599 * @var array Stores the default attributes to be stripped by strip_attributes().
600 * @see SimplePie::strip_attributes()
601 * @access private
603 public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
606 * @var array Stores the default tags to be stripped by strip_htmltags().
607 * @see SimplePie::strip_htmltags()
608 * @access private
610 public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
613 * The SimplePie class contains feed level data and options
615 * To use SimplePie, create the SimplePie object with no parameters. You can
616 * then set configuration options using the provided methods. After setting
617 * them, you must initialise the feed using $feed->init(). At that point the
618 * object's methods and properties will be available to you.
620 * Previously, it was possible to pass in the feed URL along with cache
621 * options directly into the constructor. This has been removed as of 1.3 as
622 * it caused a lot of confusion.
624 * @since 1.0 Preview Release
626 public function __construct()
628 if (version_compare(PHP_VERSION, '5.2', '<'))
630 trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
631 die();
634 // Other objects, instances created here so we can set options on them
635 $this->sanitize = new SimplePie_Sanitize();
636 $this->registry = new SimplePie_Registry();
638 if (func_num_args() > 0)
640 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
641 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);
643 $args = func_get_args();
644 switch (count($args)) {
645 case 3:
646 $this->set_cache_duration($args[2]);
647 case 2:
648 $this->set_cache_location($args[1]);
649 case 1:
650 $this->set_feed_url($args[0]);
651 $this->init();
657 * Used for converting object to a string
659 public function __toString()
661 return md5(serialize($this->data));
665 * Remove items that link back to this before destroying this object
667 public function __destruct()
669 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
671 if (!empty($this->data['items']))
673 foreach ($this->data['items'] as $item)
675 $item->__destruct();
677 unset($item, $this->data['items']);
679 if (!empty($this->data['ordered_items']))
681 foreach ($this->data['ordered_items'] as $item)
683 $item->__destruct();
685 unset($item, $this->data['ordered_items']);
691 * Force the given data/URL to be treated as a feed
693 * This tells SimplePie to ignore the content-type provided by the server.
694 * Be careful when using this option, as it will also disable autodiscovery.
696 * @since 1.1
697 * @param bool $enable Force the given data/URL to be treated as a feed
699 public function force_feed($enable = false)
701 $this->force_feed = (bool) $enable;
705 * Set the URL of the feed you want to parse
707 * This allows you to enter the URL of the feed you want to parse, or the
708 * website you want to try to use auto-discovery on. This takes priority
709 * over any set raw data.
711 * You can set multiple feeds to mash together by passing an array instead
712 * of a string for the $url. Remember that with each additional feed comes
713 * additional processing and resources.
715 * @since 1.0 Preview Release
716 * @see set_raw_data()
717 * @param string|array $url This is the URL (or array of URLs) that you want to parse.
719 public function set_feed_url($url)
721 $this->multifeed_url = array();
722 if (is_array($url))
724 foreach ($url as $value)
726 $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
729 else
731 $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
736 * Set an instance of {@see SimplePie_File} to use as a feed
738 * @param SimplePie_File &$file
739 * @return bool True on success, false on failure
741 public function set_file(&$file)
743 if ($file instanceof SimplePie_File)
745 $this->feed_url = $file->url;
746 $this->file =& $file;
747 return true;
749 return false;
753 * Set the raw XML data to parse
755 * Allows you to use a string of RSS/Atom data instead of a remote feed.
757 * If you have a feed available as a string in PHP, you can tell SimplePie
758 * to parse that data string instead of a remote feed. Any set feed URL
759 * takes precedence.
761 * @since 1.0 Beta 3
762 * @param string $data RSS or Atom data as a string.
763 * @see set_feed_url()
765 public function set_raw_data($data)
767 $this->raw_data = $data;
771 * Set the the default timeout for fetching remote feeds
773 * This allows you to change the maximum time the feed's server to respond
774 * and send the feed back.
776 * @since 1.0 Beta 3
777 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
779 public function set_timeout($timeout = 10)
781 $this->timeout = (int) $timeout;
785 * Force SimplePie to use fsockopen() instead of cURL
787 * @since 1.0 Beta 3
788 * @param bool $enable Force fsockopen() to be used
790 public function force_fsockopen($enable = false)
792 $this->force_fsockopen = (bool) $enable;
796 * Enable/disable caching in SimplePie.
798 * This option allows you to disable caching all-together in SimplePie.
799 * However, disabling the cache can lead to longer load times.
801 * @since 1.0 Preview Release
802 * @param bool $enable Enable caching
804 public function enable_cache($enable = true)
806 $this->cache = (bool) $enable;
810 * Set the length of time (in seconds) that the contents of a feed will be
811 * cached
813 * @param int $seconds The feed content cache duration
815 public function set_cache_duration($seconds = 3600)
817 $this->cache_duration = (int) $seconds;
821 * Set the length of time (in seconds) that the autodiscovered feed URL will
822 * be cached
824 * @param int $seconds The autodiscovered feed URL cache duration.
826 public function set_autodiscovery_cache_duration($seconds = 604800)
828 $this->autodiscovery_cache_duration = (int) $seconds;
832 * Set the file system location where the cached files should be stored
834 * @param string $location The file system location.
836 public function set_cache_location($location = './cache')
838 $this->cache_location = (string) $location;
842 * Set whether feed items should be sorted into reverse chronological order
844 * @param bool $enable Sort as reverse chronological order.
846 public function enable_order_by_date($enable = true)
848 $this->order_by_date = (bool) $enable;
852 * Set the character encoding used to parse the feed
854 * This overrides the encoding reported by the feed, however it will fall
855 * back to the normal encoding detection if the override fails
857 * @param string $encoding Character encoding
859 public function set_input_encoding($encoding = false)
861 if ($encoding)
863 $this->input_encoding = (string) $encoding;
865 else
867 $this->input_encoding = false;
872 * Set how much feed autodiscovery to do
874 * @see SIMPLEPIE_LOCATOR_NONE
875 * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
876 * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
877 * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
878 * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
879 * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
880 * @see SIMPLEPIE_LOCATOR_ALL
881 * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
883 public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
885 $this->autodiscovery = (int) $level;
889 * Get the class registry
891 * Use this to override SimplePie's default classes
892 * @see SimplePie_Registry
893 * @return SimplePie_Registry
895 public function &get_registry()
897 return $this->registry;
900 /**#@+
901 * Useful when you are overloading or extending SimplePie's default classes.
903 * @deprecated Use {@see get_registry()} instead
904 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
905 * @param string $class Name of custom class
906 * @return boolean True on success, false otherwise
909 * Set which class SimplePie uses for caching
911 public function set_cache_class($class = 'SimplePie_Cache')
913 return $this->registry->register('Cache', $class, true);
917 * Set which class SimplePie uses for auto-discovery
919 public function set_locator_class($class = 'SimplePie_Locator')
921 return $this->registry->register('Locator', $class, true);
925 * Set which class SimplePie uses for XML parsing
927 public function set_parser_class($class = 'SimplePie_Parser')
929 return $this->registry->register('Parser', $class, true);
933 * Set which class SimplePie uses for remote file fetching
935 public function set_file_class($class = 'SimplePie_File')
937 return $this->registry->register('File', $class, true);
941 * Set which class SimplePie uses for data sanitization
943 public function set_sanitize_class($class = 'SimplePie_Sanitize')
945 return $this->registry->register('Sanitize', $class, true);
949 * Set which class SimplePie uses for handling feed items
951 public function set_item_class($class = 'SimplePie_Item')
953 return $this->registry->register('Item', $class, true);
957 * Set which class SimplePie uses for handling author data
959 public function set_author_class($class = 'SimplePie_Author')
961 return $this->registry->register('Author', $class, true);
965 * Set which class SimplePie uses for handling category data
967 public function set_category_class($class = 'SimplePie_Category')
969 return $this->registry->register('Category', $class, true);
973 * Set which class SimplePie uses for feed enclosures
975 public function set_enclosure_class($class = 'SimplePie_Enclosure')
977 return $this->registry->register('Enclosure', $class, true);
981 * Set which class SimplePie uses for `<media:text>` captions
983 public function set_caption_class($class = 'SimplePie_Caption')
985 return $this->registry->register('Caption', $class, true);
989 * Set which class SimplePie uses for `<media:copyright>`
991 public function set_copyright_class($class = 'SimplePie_Copyright')
993 return $this->registry->register('Copyright', $class, true);
997 * Set which class SimplePie uses for `<media:credit>`
999 public function set_credit_class($class = 'SimplePie_Credit')
1001 return $this->registry->register('Credit', $class, true);
1005 * Set which class SimplePie uses for `<media:rating>`
1007 public function set_rating_class($class = 'SimplePie_Rating')
1009 return $this->registry->register('Rating', $class, true);
1013 * Set which class SimplePie uses for `<media:restriction>`
1015 public function set_restriction_class($class = 'SimplePie_Restriction')
1017 return $this->registry->register('Restriction', $class, true);
1021 * Set which class SimplePie uses for content-type sniffing
1023 public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1025 return $this->registry->register('Content_Type_Sniffer', $class, true);
1029 * Set which class SimplePie uses item sources
1031 public function set_source_class($class = 'SimplePie_Source')
1033 return $this->registry->register('Source', $class, true);
1035 /**#@-*/
1038 * Set the user agent string
1040 * @param string $ua New user agent string.
1042 public function set_useragent($ua = SIMPLEPIE_USERAGENT)
1044 $this->useragent = (string) $ua;
1048 * Set callback function to create cache filename with
1050 * @param mixed $function Callback function
1052 public function set_cache_name_function($function = 'md5')
1054 if (is_callable($function))
1056 $this->cache_name_function = $function;
1061 * Set options to make SP as fast as possible
1063 * Forgoes a substantial amount of data sanitization in favor of speed. This
1064 * turns SimplePie into a dumb parser of feeds.
1066 * @param bool $set Whether to set them or not
1068 public function set_stupidly_fast($set = false)
1070 if ($set)
1072 $this->enable_order_by_date(false);
1073 $this->remove_div(false);
1074 $this->strip_comments(false);
1075 $this->strip_htmltags(false);
1076 $this->strip_attributes(false);
1077 $this->set_image_handler(false);
1082 * Set maximum number of feeds to check with autodiscovery
1084 * @param int $max Maximum number of feeds to check
1086 public function set_max_checked_feeds($max = 10)
1088 $this->max_checked_feeds = (int) $max;
1091 public function remove_div($enable = true)
1093 $this->sanitize->remove_div($enable);
1096 public function strip_htmltags($tags = '', $encode = null)
1098 if ($tags === '')
1100 $tags = $this->strip_htmltags;
1102 $this->sanitize->strip_htmltags($tags);
1103 if ($encode !== null)
1105 $this->sanitize->encode_instead_of_strip($tags);
1109 public function encode_instead_of_strip($enable = true)
1111 $this->sanitize->encode_instead_of_strip($enable);
1114 public function strip_attributes($attribs = '')
1116 if ($attribs === '')
1118 $attribs = $this->strip_attributes;
1120 $this->sanitize->strip_attributes($attribs);
1124 * Set the output encoding
1126 * Allows you to override SimplePie's output to match that of your webpage.
1127 * This is useful for times when your webpages are not being served as
1128 * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
1129 * is similar to {@see set_input_encoding()}.
1131 * It should be noted, however, that not all character encodings can support
1132 * all characters. If your page is being served as ISO-8859-1 and you try
1133 * to display a Japanese feed, you'll likely see garbled characters.
1134 * Because of this, it is highly recommended to ensure that your webpages
1135 * are served as UTF-8.
1137 * The number of supported character encodings depends on whether your web
1138 * host supports {@link http://php.net/mbstring mbstring},
1139 * {@link http://php.net/iconv iconv}, or both. See
1140 * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
1141 * more information.
1143 * @param string $encoding
1145 public function set_output_encoding($encoding = 'UTF-8')
1147 $this->sanitize->set_output_encoding($encoding);
1150 public function strip_comments($strip = false)
1152 $this->sanitize->strip_comments($strip);
1156 * Set element/attribute key/value pairs of HTML attributes
1157 * containing URLs that need to be resolved relative to the feed
1159 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
1160 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
1161 * |q|@cite
1163 * @since 1.0
1164 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
1166 public function set_url_replacements($element_attribute = null)
1168 $this->sanitize->set_url_replacements($element_attribute);
1172 * Set the handler to enable the display of cached images.
1174 * @param str $page Web-accessible path to the handler_image.php file.
1175 * @param str $qs The query string that the value should be passed to.
1177 public function set_image_handler($page = false, $qs = 'i')
1179 if ($page !== false)
1181 $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1183 else
1185 $this->image_handler = '';
1190 * Set the limit for items returned per-feed with multifeeds
1192 * @param integer $limit The maximum number of items to return.
1194 public function set_item_limit($limit = 0)
1196 $this->item_limit = (int) $limit;
1200 * Initialize the feed object
1202 * This is what makes everything happen. Period. This is where all of the
1203 * configuration options get processed, feeds are fetched, cached, and
1204 * parsed, and all of that other good stuff.
1206 * @return boolean True if successful, false otherwise
1208 public function init()
1210 // Check absolute bare minimum requirements.
1211 if (!extension_loaded('xml') || !extension_loaded('pcre'))
1213 return false;
1215 // 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.
1216 elseif (!extension_loaded('xmlreader'))
1218 static $xml_is_sane = null;
1219 if ($xml_is_sane === null)
1221 $parser_check = xml_parser_create();
1222 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1223 xml_parser_free($parser_check);
1224 $xml_is_sane = isset($values[0]['value']);
1226 if (!$xml_is_sane)
1228 return false;
1232 if (method_exists($this->sanitize, 'set_registry'))
1234 $this->sanitize->set_registry($this->registry);
1237 // Pass whatever was set with config options over to the sanitizer.
1238 // Pass the classes in for legacy support; new classes should use the registry instead
1239 $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
1240 $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
1242 if (!empty($this->multifeed_url))
1244 $i = 0;
1245 $success = 0;
1246 $this->multifeed_objects = array();
1247 $this->error = array();
1248 foreach ($this->multifeed_url as $url)
1250 $this->multifeed_objects[$i] = clone $this;
1251 $this->multifeed_objects[$i]->set_feed_url($url);
1252 $single_success = $this->multifeed_objects[$i]->init();
1253 $success |= $single_success;
1254 if (!$single_success)
1256 $this->error[$i] = $this->multifeed_objects[$i]->error();
1258 $i++;
1260 return (bool) $success;
1262 elseif ($this->feed_url === null && $this->raw_data === null)
1264 return false;
1267 $this->error = null;
1268 $this->data = array();
1269 $this->multifeed_objects = array();
1270 $cache = false;
1272 if ($this->feed_url !== null)
1274 $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
1276 // Decide whether to enable caching
1277 if ($this->cache && $parsed_feed_url['scheme'] !== '')
1279 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
1282 // Fetch the data via SimplePie_File into $this->raw_data
1283 if (($fetched = $this->fetch_data($cache)) === true)
1285 return true;
1287 elseif ($fetched === false) {
1288 return false;
1291 list($headers, $sniffed) = $fetched;
1294 // Set up array of possible encodings
1295 $encodings = array();
1297 // First check to see if input has been overridden.
1298 if ($this->input_encoding !== false)
1300 $encodings[] = $this->input_encoding;
1303 $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1304 $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1306 // RFC 3023 (only applies to sniffed content)
1307 if (isset($sniffed))
1309 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1311 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1313 $encodings[] = strtoupper($charset[1]);
1315 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1316 $encodings[] = 'UTF-8';
1318 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1320 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1322 $encodings[] = $charset[1];
1324 $encodings[] = 'US-ASCII';
1326 // Text MIME-type default
1327 elseif (substr($sniffed, 0, 5) === 'text/')
1329 $encodings[] = 'US-ASCII';
1333 // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1334 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1335 $encodings[] = 'UTF-8';
1336 $encodings[] = 'ISO-8859-1';
1338 // There's no point in trying an encoding twice
1339 $encodings = array_unique($encodings);
1341 // Loop through each possible encoding, till we return something, or run out of possibilities
1342 foreach ($encodings as $encoding)
1344 // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1345 if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
1347 // Create new parser
1348 $parser = $this->registry->create('Parser');
1350 // If it's parsed fine
1351 if ($parser->parse($utf8_data, 'UTF-8'))
1353 $this->data = $parser->get_data();
1354 if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
1356 $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1357 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1358 return false;
1361 if (isset($headers))
1363 $this->data['headers'] = $headers;
1365 $this->data['build'] = SIMPLEPIE_BUILD;
1367 // Cache the file if caching is enabled
1368 if ($cache && !$cache->save($this))
1370 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 return true;
1377 if (isset($parser))
1379 // We have an error, just set SimplePie_Misc::error to it and quit
1380 $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());
1382 else
1384 $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.';
1387 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1389 return false;
1393 * Fetch the data via SimplePie_File
1395 * If the data is already cached, attempt to fetch it from there instead
1396 * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
1397 * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
1399 protected function fetch_data(&$cache)
1401 // If it's enabled, use the cache
1402 if ($cache)
1404 // Load the Cache
1405 $this->data = $cache->load();
1406 if (!empty($this->data))
1408 // If the cache is for an outdated build of SimplePie
1409 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1411 $cache->unlink();
1412 $this->data = array();
1414 // If we've hit a collision just rerun it with caching disabled
1415 elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1417 $cache = false;
1418 $this->data = array();
1420 // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1421 elseif (isset($this->data['feed_url']))
1423 // If the autodiscovery cache is still valid use it.
1424 if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1426 // Do not need to do feed autodiscovery yet.
1427 if ($this->data['feed_url'] !== $this->data['url'])
1429 $this->set_feed_url($this->data['feed_url']);
1430 return $this->init();
1433 $cache->unlink();
1434 $this->data = array();
1437 // Check if the cache has been updated
1438 elseif ($cache->mtime() + $this->cache_duration < time())
1440 // If we have last-modified and/or etag set
1441 if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1443 $headers = array(
1444 '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',
1446 if (isset($this->data['headers']['last-modified']))
1448 $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1450 if (isset($this->data['headers']['etag']))
1452 $headers['if-none-match'] = $this->data['headers']['etag'];
1455 $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
1457 if ($file->success)
1459 if ($file->status_code === 304)
1461 $cache->touch();
1462 return true;
1465 else
1467 unset($file);
1471 // If the cache is still valid, just return true
1472 else
1474 $this->raw_data = false;
1475 return true;
1478 // If the cache is empty, delete it
1479 else
1481 $cache->unlink();
1482 $this->data = array();
1485 // 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.
1486 if (!isset($file))
1488 if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
1490 $file =& $this->file;
1492 else
1494 $headers = array(
1495 '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',
1497 $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
1500 // If the file connection has an error, set SimplePie::error to that and quit
1501 if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1503 $this->error = $file->error;
1504 return !empty($this->data);
1507 if (!$this->force_feed)
1509 // Check if the supplied URL is a feed, if it isn't, look for it.
1510 $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
1512 if (!$locate->is_feed($file))
1514 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1515 unset($file);
1518 if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
1520 $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.";
1521 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1522 return false;
1525 catch (SimplePie_Exception $e)
1527 // This is usually because DOMDocument doesn't exist
1528 $this->error = $e->getMessage();
1529 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
1530 return false;
1532 if ($cache)
1534 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1535 if (!$cache->save($this))
1537 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);
1539 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
1541 $this->feed_url = $file->url;
1543 $locate = null;
1546 $this->raw_data = $file->body;
1548 $headers = $file->headers;
1549 $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
1550 $sniffed = $sniffer->get_type();
1552 return array($headers, $sniffed);
1556 * Get the error message for the occured error
1558 * @return string|array Error message, or array of messages for multifeeds
1560 public function error()
1562 return $this->error;
1566 * Get the raw XML
1568 * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
1569 * the data instead of printing it.
1571 * @return string|boolean Raw XML data, false if the cache is used
1573 public function get_raw_data()
1575 return $this->raw_data;
1579 * Get the character encoding used for output
1581 * @since Preview Release
1582 * @return string
1584 public function get_encoding()
1586 return $this->sanitize->output_encoding;
1590 * Send the content-type header with correct encoding
1592 * This method ensures that the SimplePie-enabled page is being served with
1593 * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
1594 * and character encoding HTTP headers (character encoding determined by the
1595 * {@see set_output_encoding} config option).
1597 * This won't work properly if any content or whitespace has already been
1598 * sent to the browser, because it relies on PHP's
1599 * {@link http://php.net/header header()} function, and these are the
1600 * circumstances under which the function works.
1602 * Because it's setting these settings for the entire page (as is the nature
1603 * of HTTP headers), this should only be used once per page (again, at the
1604 * top).
1606 * @param string $mime MIME type to serve the page as
1608 public function handle_content_type($mime = 'text/html')
1610 if (!headers_sent())
1612 $header = "Content-type: $mime;";
1613 if ($this->get_encoding())
1615 $header .= ' charset=' . $this->get_encoding();
1617 else
1619 $header .= ' charset=UTF-8';
1621 header($header);
1626 * Get the type of the feed
1628 * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
1629 * using {@link http://php.net/language.operators.bitwise bitwise operators}
1631 * @since 0.8 (usage changed to using constants in 1.0)
1632 * @see SIMPLEPIE_TYPE_NONE Unknown.
1633 * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
1634 * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
1635 * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
1636 * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
1637 * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
1638 * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
1639 * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
1640 * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
1641 * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
1642 * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
1643 * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
1644 * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
1645 * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
1646 * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
1647 * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
1648 * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
1649 * @return int SIMPLEPIE_TYPE_* constant
1651 public function get_type()
1653 if (!isset($this->data['type']))
1655 $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1656 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1658 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1660 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1662 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1664 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1666 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1667 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1668 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1669 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1671 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1673 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1674 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1675 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1676 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1678 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1681 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1683 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1684 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1686 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1688 case '0.91':
1689 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1690 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1692 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1694 case '0':
1695 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1696 break;
1698 case '24':
1699 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1700 break;
1703 break;
1705 case '0.92':
1706 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1707 break;
1709 case '0.93':
1710 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1711 break;
1713 case '0.94':
1714 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1715 break;
1717 case '2.0':
1718 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1719 break;
1723 else
1725 $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1728 return $this->data['type'];
1732 * Get the URL for the feed
1734 * May or may not be different from the URL passed to {@see set_feed_url()},
1735 * depending on whether auto-discovery was used.
1737 * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
1738 * @todo If we have a perm redirect we should return the new URL
1739 * @todo When we make the above change, let's support <itunes:new-feed-url> as well
1740 * @todo Also, |atom:link|@rel=self
1741 * @return string|null
1743 public function subscribe_url()
1745 if ($this->feed_url !== null)
1747 return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
1749 else
1751 return null;
1756 * Get data for an feed-level element
1758 * This method allows you to get access to ANY element/attribute that is a
1759 * sub-element of the opening feed tag.
1761 * The return value is an indexed array of elements matching the given
1762 * namespace and tag name. Each element has `attribs`, `data` and `child`
1763 * subkeys. For `attribs` and `child`, these contain namespace subkeys.
1764 * `attribs` then has one level of associative name => value data (where
1765 * `value` is a string) after the namespace. `child` has tag-indexed keys
1766 * after the namespace, each member of which is an indexed array matching
1767 * this same format.
1769 * For example:
1770 * <pre>
1771 * // This is probably a bad example because we already support
1772 * // <media:content> natively, but it shows you how to parse through
1773 * // the nodes.
1774 * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
1775 * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
1776 * $file = $content[0]['attribs']['']['url'];
1777 * echo $file;
1778 * </pre>
1780 * @since 1.0
1781 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1782 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1783 * @param string $tag Tag name
1784 * @return array
1786 public function get_feed_tags($namespace, $tag)
1788 $type = $this->get_type();
1789 if ($type & SIMPLEPIE_TYPE_ATOM_10)
1791 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1793 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1796 if ($type & SIMPLEPIE_TYPE_ATOM_03)
1798 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1800 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1803 if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1805 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
1807 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
1810 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1812 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
1814 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
1817 return null;
1821 * Get data for an channel-level element
1823 * This method allows you to get access to ANY element/attribute in the
1824 * channel/header section of the feed.
1826 * See {@see SimplePie::get_feed_tags()} for a description of the return value
1828 * @since 1.0
1829 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1830 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1831 * @param string $tag Tag name
1832 * @return array
1834 public function get_channel_tags($namespace, $tag)
1836 $type = $this->get_type();
1837 if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
1839 if ($return = $this->get_feed_tags($namespace, $tag))
1841 return $return;
1844 if ($type & SIMPLEPIE_TYPE_RSS_10)
1846 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
1848 if (isset($channel[0]['child'][$namespace][$tag]))
1850 return $channel[0]['child'][$namespace][$tag];
1854 if ($type & SIMPLEPIE_TYPE_RSS_090)
1856 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
1858 if (isset($channel[0]['child'][$namespace][$tag]))
1860 return $channel[0]['child'][$namespace][$tag];
1864 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1866 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
1868 if (isset($channel[0]['child'][$namespace][$tag]))
1870 return $channel[0]['child'][$namespace][$tag];
1874 return null;
1878 * Get data for an channel-level element
1880 * This method allows you to get access to ANY element/attribute in the
1881 * image/logo section of the feed.
1883 * See {@see SimplePie::get_feed_tags()} for a description of the return value
1885 * @since 1.0
1886 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1887 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1888 * @param string $tag Tag name
1889 * @return array
1891 public function get_image_tags($namespace, $tag)
1893 $type = $this->get_type();
1894 if ($type & SIMPLEPIE_TYPE_RSS_10)
1896 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1898 if (isset($image[0]['child'][$namespace][$tag]))
1900 return $image[0]['child'][$namespace][$tag];
1904 if ($type & SIMPLEPIE_TYPE_RSS_090)
1906 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1908 if (isset($image[0]['child'][$namespace][$tag]))
1910 return $image[0]['child'][$namespace][$tag];
1914 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1916 if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
1918 if (isset($image[0]['child'][$namespace][$tag]))
1920 return $image[0]['child'][$namespace][$tag];
1924 return null;
1928 * Get the base URL value from the feed
1930 * Uses `<xml:base>` if available, otherwise uses the first link in the
1931 * feed, or failing that, the URL of the feed itself.
1933 * @see get_link
1934 * @see subscribe_url
1936 * @param array $element
1937 * @return string
1939 public function get_base($element = array())
1941 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
1943 return $element['xml_base'];
1945 elseif ($this->get_link() !== null)
1947 return $this->get_link();
1949 else
1951 return $this->subscribe_url();
1956 * Sanitize feed data
1958 * @access private
1959 * @see SimplePie_Sanitize::sanitize()
1960 * @param string $data Data to sanitize
1961 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
1962 * @param string $base Base URL to resolve URLs against
1963 * @return string Sanitized data
1965 public function sanitize($data, $type, $base = '')
1967 return $this->sanitize->sanitize($data, $type, $base);
1971 * Get the title of the feed
1973 * Uses `<atom:title>`, `<title>` or `<dc:title>`
1975 * @since 1.0 (previously called `get_feed_title` since 0.8)
1976 * @return string|null
1978 public function get_title()
1980 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
1982 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1984 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
1986 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1988 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1990 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1992 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1994 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1996 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
1998 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2000 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2002 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2004 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2006 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2008 else
2010 return null;
2015 * Get a category for the feed
2017 * @since Unknown
2018 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
2019 * @return SimplePie_Category|null
2021 public function get_category($key = 0)
2023 $categories = $this->get_categories();
2024 if (isset($categories[$key]))
2026 return $categories[$key];
2028 else
2030 return null;
2035 * Get all categories for the feed
2037 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
2039 * @since Unknown
2040 * @return array|null List of {@see SimplePie_Category} objects
2042 public function get_categories()
2044 $categories = array();
2046 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2048 $term = null;
2049 $scheme = null;
2050 $label = null;
2051 if (isset($category['attribs']['']['term']))
2053 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2055 if (isset($category['attribs']['']['scheme']))
2057 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2059 if (isset($category['attribs']['']['label']))
2061 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2063 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
2065 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2067 // This is really the label, but keep this as the term also for BC.
2068 // Label will also work on retrieving because that falls back to term.
2069 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2070 if (isset($category['attribs']['']['domain']))
2072 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2074 else
2076 $scheme = null;
2078 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
2080 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2082 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2084 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2086 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2089 if (!empty($categories))
2091 return array_unique($categories);
2093 else
2095 return null;
2100 * Get an author for the feed
2102 * @since 1.1
2103 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
2104 * @return SimplePie_Author|null
2106 public function get_author($key = 0)
2108 $authors = $this->get_authors();
2109 if (isset($authors[$key]))
2111 return $authors[$key];
2113 else
2115 return null;
2120 * Get all authors for the feed
2122 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
2124 * @since 1.1
2125 * @return array|null List of {@see SimplePie_Author} objects
2127 public function get_authors()
2129 $authors = array();
2130 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2132 $name = null;
2133 $uri = null;
2134 $email = null;
2135 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2137 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2139 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2141 $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]));
2143 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2145 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2147 if ($name !== null || $email !== null || $uri !== null)
2149 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
2152 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2154 $name = null;
2155 $url = null;
2156 $email = null;
2157 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2159 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2161 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2163 $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]));
2165 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2167 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2169 if ($name !== null || $email !== null || $url !== null)
2171 $authors[] = $this->registry->create('Author', array($name, $url, $email));
2174 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2176 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2178 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2180 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2182 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2184 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2187 if (!empty($authors))
2189 return array_unique($authors);
2191 else
2193 return null;
2198 * Get a contributor for the feed
2200 * @since 1.1
2201 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
2202 * @return SimplePie_Author|null
2204 public function get_contributor($key = 0)
2206 $contributors = $this->get_contributors();
2207 if (isset($contributors[$key]))
2209 return $contributors[$key];
2211 else
2213 return null;
2218 * Get all contributors for the feed
2220 * Uses `<atom:contributor>`
2222 * @since 1.1
2223 * @return array|null List of {@see SimplePie_Author} objects
2225 public function get_contributors()
2227 $contributors = array();
2228 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2230 $name = null;
2231 $uri = null;
2232 $email = null;
2233 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2235 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2237 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2239 $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]));
2241 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2243 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2245 if ($name !== null || $email !== null || $uri !== null)
2247 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
2250 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2252 $name = null;
2253 $url = null;
2254 $email = null;
2255 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2257 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2259 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2261 $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]));
2263 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2265 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2267 if ($name !== null || $email !== null || $url !== null)
2269 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
2273 if (!empty($contributors))
2275 return array_unique($contributors);
2277 else
2279 return null;
2284 * Get a single link for the feed
2286 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2287 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
2288 * @param string $rel The relationship of the link to return
2289 * @return string|null Link URL
2291 public function get_link($key = 0, $rel = 'alternate')
2293 $links = $this->get_links($rel);
2294 if (isset($links[$key]))
2296 return $links[$key];
2298 else
2300 return null;
2305 * Get the permalink for the item
2307 * Returns the first link available with a relationship of "alternate".
2308 * Identical to {@see get_link()} with key 0
2310 * @see get_link
2311 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2312 * @internal Added for parity between the parent-level and the item/entry-level.
2313 * @return string|null Link URL
2315 public function get_permalink()
2317 return $this->get_link(0);
2321 * Get all links for the feed
2323 * Uses `<atom:link>` or `<link>`
2325 * @since Beta 2
2326 * @param string $rel The relationship of links to return
2327 * @return array|null Links found for the feed (strings)
2329 public function get_links($rel = 'alternate')
2331 if (!isset($this->data['links']))
2333 $this->data['links'] = array();
2334 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2336 foreach ($links as $link)
2338 if (isset($link['attribs']['']['href']))
2340 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2341 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2345 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2347 foreach ($links as $link)
2349 if (isset($link['attribs']['']['href']))
2351 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2352 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2357 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2359 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2361 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2363 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2365 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2367 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2370 $keys = array_keys($this->data['links']);
2371 foreach ($keys as $key)
2373 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
2375 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2377 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2378 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2380 else
2382 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2385 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2387 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2389 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2393 if (isset($this->data['links'][$rel]))
2395 return $this->data['links'][$rel];
2397 else
2399 return null;
2403 public function get_all_discovered_feeds()
2405 return $this->all_discovered_feeds;
2409 * Get the content for the item
2411 * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
2412 * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
2414 * @since 1.0 (previously called `get_feed_description()` since 0.8)
2415 * @return string|null
2417 public function get_description()
2419 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2421 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2423 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2425 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2427 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2429 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2431 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2433 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2435 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2437 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2439 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2441 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2443 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2445 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2447 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2449 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2451 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2453 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2455 else
2457 return null;
2462 * Get the copyright info for the feed
2464 * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
2466 * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
2467 * @return string|null
2469 public function get_copyright()
2471 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2473 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2475 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2477 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2479 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2481 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2483 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2485 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2487 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2489 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2491 else
2493 return null;
2498 * Get the language for the feed
2500 * Uses `<language>`, `<dc:language>`, or @xml_lang
2502 * @since 1.0 (previously called `get_feed_language()` since 0.8)
2503 * @return string|null
2505 public function get_language()
2507 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2509 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2511 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2513 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2515 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2517 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2519 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2521 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2523 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2525 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2527 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2529 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2531 elseif (isset($this->data['headers']['content-language']))
2533 return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2535 else
2537 return null;
2542 * Get the latitude coordinates for the item
2544 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2546 * Uses `<geo:lat>` or `<georss:point>`
2548 * @since 1.0
2549 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2550 * @link http://www.georss.org/ GeoRSS
2551 * @return string|null
2553 public function get_latitude()
2556 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2558 return (float) $return[0]['data'];
2560 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))
2562 return (float) $match[1];
2564 else
2566 return null;
2571 * Get the longitude coordinates for the feed
2573 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2575 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2577 * @since 1.0
2578 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2579 * @link http://www.georss.org/ GeoRSS
2580 * @return string|null
2582 public function get_longitude()
2584 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2586 return (float) $return[0]['data'];
2588 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2590 return (float) $return[0]['data'];
2592 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))
2594 return (float) $match[2];
2596 else
2598 return null;
2603 * Get the feed logo's title
2605 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
2607 * Uses `<image><title>` or `<image><dc:title>`
2609 * @return string|null
2611 public function get_image_title()
2613 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2615 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2617 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2619 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2621 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2623 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2625 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2627 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2629 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2631 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2633 else
2635 return null;
2640 * Get the feed logo's URL
2642 * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
2643 * have a "feed logo" URL. This points directly to the image itself.
2645 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2646 * `<image><title>` or `<image><dc:title>`
2648 * @return string|null
2650 public function get_image_url()
2652 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2654 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2656 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2658 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2660 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2662 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2664 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2666 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2668 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2670 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2672 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2674 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2676 else
2678 return null;
2683 * Get the feed logo's link
2685 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
2686 * points to a human-readable page that the image should link to.
2688 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2689 * `<image><title>` or `<image><dc:title>`
2691 * @return string|null
2693 public function get_image_link()
2695 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2697 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2699 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2701 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2703 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2705 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2707 else
2709 return null;
2714 * Get the feed logo's link
2716 * RSS 2.0 feeds are allowed to have a "feed logo" width.
2718 * Uses `<image><width>` or defaults to 88.0 if no width is specified and
2719 * the feed is an RSS 2.0 feed.
2721 * @return int|float|null
2723 public function get_image_width()
2725 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2727 return round($return[0]['data']);
2729 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2731 return 88.0;
2733 else
2735 return null;
2740 * Get the feed logo's height
2742 * RSS 2.0 feeds are allowed to have a "feed logo" height.
2744 * Uses `<image><height>` or defaults to 31.0 if no height is specified and
2745 * the feed is an RSS 2.0 feed.
2747 * @return int|float|null
2749 public function get_image_height()
2751 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2753 return round($return[0]['data']);
2755 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2757 return 31.0;
2759 else
2761 return null;
2766 * Get the number of items in the feed
2768 * This is well-suited for {@link http://php.net/for for()} loops with
2769 * {@see get_item()}
2771 * @param int $max Maximum value to return. 0 for no limit
2772 * @return int Number of items in the feed
2774 public function get_item_quantity($max = 0)
2776 $max = (int) $max;
2777 $qty = count($this->get_items());
2778 if ($max === 0)
2780 return $qty;
2782 else
2784 return ($qty > $max) ? $max : $qty;
2789 * Get a single item from the feed
2791 * This is better suited for {@link http://php.net/for for()} loops, whereas
2792 * {@see get_items()} is better suited for
2793 * {@link http://php.net/foreach foreach()} loops.
2795 * @see get_item_quantity()
2796 * @since Beta 2
2797 * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
2798 * @return SimplePie_Item|null
2800 public function get_item($key = 0)
2802 $items = $this->get_items();
2803 if (isset($items[$key]))
2805 return $items[$key];
2807 else
2809 return null;
2814 * Get all items from the feed
2816 * This is better suited for {@link http://php.net/for for()} loops, whereas
2817 * {@see get_items()} is better suited for
2818 * {@link http://php.net/foreach foreach()} loops.
2820 * @see get_item_quantity
2821 * @since Beta 2
2822 * @param int $start Index to start at
2823 * @param int $end Number of items to return. 0 for all items after `$start`
2824 * @return array|null List of {@see SimplePie_Item} objects
2826 public function get_items($start = 0, $end = 0)
2828 if (!isset($this->data['items']))
2830 if (!empty($this->multifeed_objects))
2832 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
2834 else
2836 $this->data['items'] = array();
2837 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
2839 $keys = array_keys($items);
2840 foreach ($keys as $key)
2842 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2845 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
2847 $keys = array_keys($items);
2848 foreach ($keys as $key)
2850 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2853 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
2855 $keys = array_keys($items);
2856 foreach ($keys as $key)
2858 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2861 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2863 $keys = array_keys($items);
2864 foreach ($keys as $key)
2866 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2869 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
2871 $keys = array_keys($items);
2872 foreach ($keys as $key)
2874 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2880 if (!empty($this->data['items']))
2882 // If we want to order it by date, check if all items have a date, and then sort it
2883 if ($this->order_by_date && empty($this->multifeed_objects))
2885 if (!isset($this->data['ordered_items']))
2887 $do_sort = true;
2888 foreach ($this->data['items'] as $item)
2890 if (!$item->get_date('U'))
2892 $do_sort = false;
2893 break;
2896 $item = null;
2897 $this->data['ordered_items'] = $this->data['items'];
2898 if ($do_sort)
2900 usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
2903 $items = $this->data['ordered_items'];
2905 else
2907 $items = $this->data['items'];
2910 // Slice the data as desired
2911 if ($end === 0)
2913 return array_slice($items, $start);
2915 else
2917 return array_slice($items, $start, $end);
2920 else
2922 return array();
2927 * Set the favicon handler
2929 * @deprecated Use your own favicon handling instead
2931 public function set_favicon_handler($page = false, $qs = 'i')
2933 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2934 trigger_error('Favicon handling has been removed, please use your own handling', $level);
2935 return false;
2939 * Get the favicon for the current feed
2941 * @deprecated Use your own favicon handling instead
2943 public function get_favicon()
2945 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2946 trigger_error('Favicon handling has been removed, please use your own handling', $level);
2948 if (($url = $this->get_link()) !== null)
2950 return 'http://g.etfv.co/' . urlencode($url);
2953 return false;
2957 * Magic method handler
2959 * @param string $method Method name
2960 * @param array $args Arguments to the method
2961 * @return mixed
2963 public function __call($method, $args)
2965 if (strpos($method, 'subscribe_') === 0)
2967 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2968 trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
2969 return '';
2971 if ($method === 'enable_xml_dump')
2973 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2974 trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
2975 return false;
2978 $class = get_class($this);
2979 $trace = debug_backtrace();
2980 $file = $trace[0]['file'];
2981 $line = $trace[0]['line'];
2982 trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
2986 * Sorting callback for items
2988 * @access private
2989 * @param SimplePie $a
2990 * @param SimplePie $b
2991 * @return boolean
2993 public static function sort_items($a, $b)
2995 return $a->get_date('U') <= $b->get_date('U');
2999 * Merge items from several feeds into one
3001 * If you're merging multiple feeds together, they need to all have dates
3002 * for the items or else SimplePie will refuse to sort them.
3004 * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
3005 * @param array $urls List of SimplePie feed objects to merge
3006 * @param int $start Starting item
3007 * @param int $end Number of items to return
3008 * @param int $limit Maximum number of items per feed
3009 * @return array
3011 public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
3013 if (is_array($urls) && sizeof($urls) > 0)
3015 $items = array();
3016 foreach ($urls as $arg)
3018 if ($arg instanceof SimplePie)
3020 $items = array_merge($items, $arg->get_items(0, $limit));
3022 else
3024 trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
3028 $do_sort = true;
3029 foreach ($items as $item)
3031 if (!$item->get_date('U'))
3033 $do_sort = false;
3034 break;
3037 $item = null;
3038 if ($do_sort)
3040 usort($items, array(get_class($urls[0]), 'sort_items'));
3043 if ($end === 0)
3045 return array_slice($items, $start);
3047 else
3049 return array_slice($items, $start, $end);
3052 else
3054 trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
3055 return array();
3061 * Manages all author-related data
3063 * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
3065 * This class can be overloaded with {@see SimplePie::set_author_class()}
3067 * @package SimplePie
3068 * @subpackage API
3070 class SimplePie_Author
3073 * Author's name
3075 * @var string
3076 * @see get_name()
3078 var $name;
3081 * Author's link
3083 * @var string
3084 * @see get_link()
3086 var $link;
3089 * Author's email address
3091 * @var string
3092 * @see get_email()
3094 var $email;
3097 * Constructor, used to input the data
3099 * @param string $name
3100 * @param string $link
3101 * @param string $email
3103 public function __construct($name = null, $link = null, $email = null)
3105 $this->name = $name;
3106 $this->link = $link;
3107 $this->email = $email;
3111 * String-ified version
3113 * @return string
3115 public function __toString()
3117 // There is no $this->data here
3118 return md5(serialize($this));
3122 * Author's name
3124 * @return string|null
3126 public function get_name()
3128 if ($this->name !== null)
3130 return $this->name;
3132 else
3134 return null;
3139 * Author's link
3141 * @return string|null
3143 public function get_link()
3145 if ($this->link !== null)
3147 return $this->link;
3149 else
3151 return null;
3156 * Author's email address
3158 * @return string|null
3160 public function get_email()
3162 if ($this->email !== null)
3164 return $this->email;
3166 else
3168 return null;
3174 * Base for cache objects
3176 * Classes to be used with {@see SimplePie_Cache::register()} are expected
3177 * to implement this interface.
3179 * @package SimplePie
3180 * @subpackage Caching
3182 interface SimplePie_Cache_Base
3185 * Feed cache type
3187 * @var string
3189 const TYPE_FEED = 'spc';
3192 * Image cache type
3194 * @var string
3196 const TYPE_IMAGE = 'spi';
3199 * Create a new cache object
3201 * @param string $location Location string (from SimplePie::$cache_location)
3202 * @param string $name Unique ID for the cache
3203 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3205 public function __construct($location, $name, $type);
3208 * Save data to the cache
3210 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3211 * @return bool Successfulness
3213 public function save($data);
3216 * Retrieve the data saved to the cache
3218 * @return array Data for SimplePie::$data
3220 public function load();
3223 * Retrieve the last modified time for the cache
3225 * @return int Timestamp
3227 public function mtime();
3230 * Set the last modified time to the current time
3232 * @return bool Success status
3234 public function touch();
3237 * Remove the cache
3239 * @return bool Success status
3241 public function unlink();
3245 * Base class for database-based caches
3247 * @package SimplePie
3248 * @subpackage Caching
3250 abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
3253 * Helper for database conversion
3255 * Converts a given {@see SimplePie} object into data to be stored
3257 * @param SimplePie $data
3258 * @return array First item is the serialized data for storage, second item is the unique ID for this item
3260 protected static function prepare_simplepie_object_for_cache($data)
3262 $items = $data->get_items();
3263 $items_by_id = array();
3265 if (!empty($items))
3267 foreach ($items as $item)
3269 $items_by_id[$item->get_id()] = $item;
3272 if (count($items_by_id) !== count($items))
3274 $items_by_id = array();
3275 foreach ($items as $item)
3277 $items_by_id[$item->get_id(true)] = $item;
3281 if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
3283 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
3285 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
3287 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
3289 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
3291 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
3293 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
3295 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
3297 else
3299 $channel = null;
3302 if ($channel !== null)
3304 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
3306 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
3308 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
3310 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
3312 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
3314 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
3316 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
3318 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
3320 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
3322 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
3325 if (isset($data->data['items']))
3327 unset($data->data['items']);
3329 if (isset($data->data['ordered_items']))
3331 unset($data->data['ordered_items']);
3334 return array(serialize($data->data), $items_by_id);
3339 * Caches data to the filesystem
3341 * @package SimplePie
3342 * @subpackage Caching
3344 class SimplePie_Cache_File implements SimplePie_Cache_Base
3347 * Location string
3349 * @see SimplePie::$cache_location
3350 * @var string
3352 protected $location;
3355 * Filename
3357 * @var string
3359 protected $filename;
3362 * File extension
3364 * @var string
3366 protected $extension;
3369 * File path
3371 * @var string
3373 protected $name;
3376 * Create a new cache object
3378 * @param string $location Location string (from SimplePie::$cache_location)
3379 * @param string $name Unique ID for the cache
3380 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3382 public function __construct($location, $name, $type)
3384 $this->location = $location;
3385 $this->filename = $name;
3386 $this->extension = $type;
3387 $this->name = "$this->location/$this->filename.$this->extension";
3391 * Save data to the cache
3393 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3394 * @return bool Successfulness
3396 public function save($data)
3398 if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
3400 if ($data instanceof SimplePie)
3402 $data = $data->data;
3405 $data = serialize($data);
3406 return (bool) file_put_contents($this->name, $data);
3408 return false;
3412 * Retrieve the data saved to the cache
3414 * @return array Data for SimplePie::$data
3416 public function load()
3418 if (file_exists($this->name) && is_readable($this->name))
3420 return unserialize(file_get_contents($this->name));
3422 return false;
3426 * Retrieve the last modified time for the cache
3428 * @return int Timestamp
3430 public function mtime()
3432 if (file_exists($this->name))
3434 return filemtime($this->name);
3436 return false;
3440 * Set the last modified time to the current time
3442 * @return bool Success status
3444 public function touch()
3446 if (file_exists($this->name))
3448 return touch($this->name);
3450 return false;
3454 * Remove the cache
3456 * @return bool Success status
3458 public function unlink()
3460 if (file_exists($this->name))
3462 return unlink($this->name);
3464 return false;
3469 * Caches data to memcache
3471 * Registered for URLs with the "memcache" protocol
3473 * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
3474 * connect to memcache on `localhost` on port 11211. All tables will be
3475 * prefixed with `sp_` and data will expire after 3600 seconds
3477 * @package SimplePie
3478 * @subpackage Caching
3479 * @uses Memcache
3481 class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
3484 * Memcache instance
3486 * @var Memcache
3488 protected $cache;
3491 * Options
3493 * @var array
3495 protected $options;
3498 * Cache name
3500 * @var string
3502 protected $name;
3505 * Create a new cache object
3507 * @param string $location Location string (from SimplePie::$cache_location)
3508 * @param string $name Unique ID for the cache
3509 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3511 public function __construct($location, $name, $type)
3513 $this->options = array(
3514 'host' => '127.0.0.1',
3515 'port' => 11211,
3516 'extras' => array(
3517 'timeout' => 3600, // one hour
3518 'prefix' => 'simplepie_',
3521 $parsed = SimplePie_Cache::parse_URL($location);
3522 $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
3523 $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
3524 $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
3525 $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
3527 $this->cache = new Memcache();
3528 $this->cache->addServer($this->options['host'], (int) $this->options['port']);
3532 * Save data to the cache
3534 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3535 * @return bool Successfulness
3537 public function save($data)
3539 if ($data instanceof SimplePie)
3541 $data = $data->data;
3543 return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
3547 * Retrieve the data saved to the cache
3549 * @return array Data for SimplePie::$data
3551 public function load()
3553 $data = $this->cache->get($this->name);
3555 if ($data !== false)
3557 return unserialize($data);
3559 return false;
3563 * Retrieve the last modified time for the cache
3565 * @return int Timestamp
3567 public function mtime()
3569 $data = $this->cache->get($this->name);
3571 if ($data !== false)
3573 // essentially ignore the mtime because Memcache expires on it's own
3574 return time();
3577 return false;
3581 * Set the last modified time to the current time
3583 * @return bool Success status
3585 public function touch()
3587 $data = $this->cache->get($this->name);
3589 if ($data !== false)
3591 return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
3594 return false;
3598 * Remove the cache
3600 * @return bool Success status
3602 public function unlink()
3604 return $this->cache->delete($this->name, 0);
3609 * Caches data to a MySQL database
3611 * Registered for URLs with the "mysql" protocol
3613 * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
3614 * connect to the `mydb` database on `localhost` on port 3306, with the user
3615 * `root` and the password `password`. All tables will be prefixed with `sp_`
3617 * @package SimplePie
3618 * @subpackage Caching
3620 class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
3623 * PDO instance
3625 * @var PDO
3627 protected $mysql;
3630 * Options
3632 * @var array
3634 protected $options;
3637 * Cache ID
3639 * @var string
3641 protected $id;
3644 * Create a new cache object
3646 * @param string $location Location string (from SimplePie::$cache_location)
3647 * @param string $name Unique ID for the cache
3648 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3650 public function __construct($location, $name, $type)
3652 $this->options = array(
3653 'user' => null,
3654 'pass' => null,
3655 'host' => '127.0.0.1',
3656 'port' => '3306',
3657 'path' => '',
3658 'extras' => array(
3659 'prefix' => '',
3662 $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
3664 // Path is prefixed with a "/"
3665 $this->options['dbname'] = substr($this->options['path'], 1);
3669 $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'));
3671 catch (PDOException $e)
3673 $this->mysql = null;
3674 return;
3677 $this->id = $name . $type;
3679 if (!$query = $this->mysql->query('SHOW TABLES'))
3681 $this->mysql = null;
3682 return;
3685 $db = array();
3686 while ($row = $query->fetchColumn())
3688 $db[] = $row;
3691 if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
3693 $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)))');
3694 if ($query === false)
3696 $this->mysql = null;
3700 if (!in_array($this->options['extras']['prefix'] . 'items', $db))
3702 $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)))');
3703 if ($query === false)
3705 $this->mysql = null;
3711 * Save data to the cache
3713 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3714 * @return bool Successfulness
3716 public function save($data)
3718 if ($this->mysql === null)
3720 return false;
3723 if ($data instanceof SimplePie)
3725 $data = clone $data;
3727 $prepared = self::prepare_simplepie_object_for_cache($data);
3729 $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
3730 $query->bindValue(':feed', $this->id);
3731 if ($query->execute())
3733 if ($query->fetchColumn() > 0)
3735 $items = count($prepared[1]);
3736 if ($items)
3738 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
3739 $query = $this->mysql->prepare($sql);
3740 $query->bindValue(':items', $items);
3742 else
3744 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
3745 $query = $this->mysql->prepare($sql);
3748 $query->bindValue(':data', $prepared[0]);
3749 $query->bindValue(':time', time());
3750 $query->bindValue(':feed', $this->id);
3751 if (!$query->execute())
3753 return false;
3756 else
3758 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
3759 $query->bindValue(':feed', $this->id);
3760 $query->bindValue(':count', count($prepared[1]));
3761 $query->bindValue(':data', $prepared[0]);
3762 $query->bindValue(':time', time());
3763 if (!$query->execute())
3765 return false;
3769 $ids = array_keys($prepared[1]);
3770 if (!empty($ids))
3772 foreach ($ids as $id)
3774 $database_ids[] = $this->mysql->quote($id);
3777 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
3778 $query->bindValue(':feed', $this->id);
3780 if ($query->execute())
3782 $existing_ids = array();
3783 while ($row = $query->fetchColumn())
3785 $existing_ids[] = $row;
3788 $new_ids = array_diff($ids, $existing_ids);
3790 foreach ($new_ids as $new_id)
3792 if (!($date = $prepared[1][$new_id]->get_date('U')))
3794 $date = time();
3797 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
3798 $query->bindValue(':feed', $this->id);
3799 $query->bindValue(':id', $new_id);
3800 $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
3801 $query->bindValue(':date', $date);
3802 if (!$query->execute())
3804 return false;
3807 return true;
3810 else
3812 return true;
3816 else
3818 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
3819 $query->bindValue(':feed', $this->id);
3820 if ($query->execute())
3822 if ($query->rowCount() > 0)
3824 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
3825 $query->bindValue(':data', serialize($data));
3826 $query->bindValue(':time', time());
3827 $query->bindValue(':feed', $this->id);
3828 if ($this->execute())
3830 return true;
3833 else
3835 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
3836 $query->bindValue(':id', $this->id);
3837 $query->bindValue(':data', serialize($data));
3838 $query->bindValue(':time', time());
3839 if ($query->execute())
3841 return true;
3846 return false;
3850 * Retrieve the data saved to the cache
3852 * @return array Data for SimplePie::$data
3854 public function load()
3856 if ($this->mysql === null)
3858 return false;
3861 $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3862 $query->bindValue(':id', $this->id);
3863 if ($query->execute() && ($row = $query->fetch()))
3865 $data = unserialize($row[1]);
3867 if (isset($this->options['items'][0]))
3869 $items = (int) $this->options['items'][0];
3871 else
3873 $items = (int) $row[0];
3876 if ($items !== 0)
3878 if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
3880 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
3882 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
3884 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
3886 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
3888 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
3890 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
3892 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
3894 else
3896 $feed = null;
3899 if ($feed !== null)
3901 $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
3902 if ($items > 0)
3904 $sql .= ' LIMIT ' . $items;
3907 $query = $this->mysql->prepare($sql);
3908 $query->bindValue(':feed', $this->id);
3909 if ($query->execute())
3911 while ($row = $query->fetchColumn())
3913 $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
3916 else
3918 return false;
3922 return $data;
3924 return false;
3928 * Retrieve the last modified time for the cache
3930 * @return int Timestamp
3932 public function mtime()
3934 if ($this->mysql === null)
3936 return false;
3939 $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3940 $query->bindValue(':id', $this->id);
3941 if ($query->execute() && ($time = $query->fetchColumn()))
3943 return $time;
3945 else
3947 return false;
3952 * Set the last modified time to the current time
3954 * @return bool Success status
3956 public function touch()
3958 if ($this->mysql === null)
3960 return false;
3963 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
3964 $query->bindValue(':time', time());
3965 $query->bindValue(':id', $this->id);
3966 if ($query->execute() && $query->rowCount() > 0)
3968 return true;
3970 else
3972 return false;
3977 * Remove the cache
3979 * @return bool Success status
3981 public function unlink()
3983 if ($this->mysql === null)
3985 return false;
3988 $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3989 $query->bindValue(':id', $this->id);
3990 $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
3991 $query2->bindValue(':id', $this->id);
3992 if ($query->execute() && $query2->execute())
3994 return true;
3996 else
3998 return false;
4004 * Used to create cache objects
4006 * This class can be overloaded with {@see SimplePie::set_cache_class()},
4007 * although the preferred way is to create your own handler
4008 * via {@see register()}
4010 * @package SimplePie
4011 * @subpackage Caching
4013 class SimplePie_Cache
4016 * Cache handler classes
4018 * These receive 3 parameters to their constructor, as documented in
4019 * {@see register()}
4020 * @var array
4022 protected static $handlers = array(
4023 'mysql' => 'SimplePie_Cache_MySQL',
4024 'memcache' => 'SimplePie_Cache_Memcache',
4028 * Don't call the constructor. Please.
4030 private function __construct() { }
4033 * Create a new SimplePie_Cache object
4035 * @param string $location URL location (scheme is used to determine handler)
4036 * @param string $filename Unique identifier for cache object
4037 * @param string $extension 'spi' or 'spc'
4038 * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
4040 public static function get_handler($location, $filename, $extension)
4042 $type = explode(':', $location, 2);
4043 $type = $type[0];
4044 if (!empty(self::$handlers[$type]))
4046 $class = self::$handlers[$type];
4047 return new $class($location, $filename, $extension);
4050 return new SimplePie_Cache_File($location, $filename, $extension);
4054 * Create a new SimplePie_Cache object
4056 * @deprecated Use {@see get_handler} instead
4058 public function create($location, $filename, $extension)
4060 trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
4061 return self::get_handler($location, $filename, $extension);
4065 * Register a handler
4067 * @param string $type DSN type to register for
4068 * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
4070 public static function register($type, $class)
4072 self::$handlers[$type] = $class;
4076 * Parse a URL into an array
4078 * @param string $url
4079 * @return array
4081 public static function parse_URL($url)
4083 $params = parse_url($url);
4084 $params['extras'] = array();
4085 if (isset($params['query']))
4087 parse_str($params['query'], $params['extras']);
4089 return $params;
4094 * Handles `<media:text>` captions as defined in Media RSS.
4096 * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
4098 * This class can be overloaded with {@see SimplePie::set_caption_class()}
4100 * @package SimplePie
4101 * @subpackage API
4103 class SimplePie_Caption
4106 * Content type
4108 * @var string
4109 * @see get_type()
4111 var $type;
4114 * Language
4116 * @var string
4117 * @see get_language()
4119 var $lang;
4122 * Start time
4124 * @var string
4125 * @see get_starttime()
4127 var $startTime;
4130 * End time
4132 * @var string
4133 * @see get_endtime()
4135 var $endTime;
4138 * Caption text
4140 * @var string
4141 * @see get_text()
4143 var $text;
4146 * Constructor, used to input the data
4148 * For documentation on all the parameters, see the corresponding
4149 * properties and their accessors
4151 public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
4153 $this->type = $type;
4154 $this->lang = $lang;
4155 $this->startTime = $startTime;
4156 $this->endTime = $endTime;
4157 $this->text = $text;
4161 * String-ified version
4163 * @return string
4165 public function __toString()
4167 // There is no $this->data here
4168 return md5(serialize($this));
4172 * Get the end time
4174 * @return string|null Time in the format 'hh:mm:ss.SSS'
4176 public function get_endtime()
4178 if ($this->endTime !== null)
4180 return $this->endTime;
4182 else
4184 return null;
4189 * Get the language
4191 * @link http://tools.ietf.org/html/rfc3066
4192 * @return string|null Language code as per RFC 3066
4194 public function get_language()
4196 if ($this->lang !== null)
4198 return $this->lang;
4200 else
4202 return null;
4207 * Get the start time
4209 * @return string|null Time in the format 'hh:mm:ss.SSS'
4211 public function get_starttime()
4213 if ($this->startTime !== null)
4215 return $this->startTime;
4217 else
4219 return null;
4224 * Get the text of the caption
4226 * @return string|null
4228 public function get_text()
4230 if ($this->text !== null)
4232 return $this->text;
4234 else
4236 return null;
4241 * Get the content type (not MIME type)
4243 * @return string|null Either 'text' or 'html'
4245 public function get_type()
4247 if ($this->type !== null)
4249 return $this->type;
4251 else
4253 return null;
4259 * Manages all category-related data
4261 * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
4263 * This class can be overloaded with {@see SimplePie::set_category_class()}
4265 * @package SimplePie
4266 * @subpackage API
4268 class SimplePie_Category
4271 * Category identifier
4273 * @var string
4274 * @see get_term
4276 var $term;
4279 * Categorization scheme identifier
4281 * @var string
4282 * @see get_scheme()
4284 var $scheme;
4287 * Human readable label
4289 * @var string
4290 * @see get_label()
4292 var $label;
4295 * Constructor, used to input the data
4297 * @param string $term
4298 * @param string $scheme
4299 * @param string $label
4301 public function __construct($term = null, $scheme = null, $label = null)
4303 $this->term = $term;
4304 $this->scheme = $scheme;
4305 $this->label = $label;
4309 * String-ified version
4311 * @return string
4313 public function __toString()
4315 // There is no $this->data here
4316 return md5(serialize($this));
4320 * Get the category identifier
4322 * @return string|null
4324 public function get_term()
4326 if ($this->term !== null)
4328 return $this->term;
4330 else
4332 return null;
4337 * Get the categorization scheme identifier
4339 * @return string|null
4341 public function get_scheme()
4343 if ($this->scheme !== null)
4345 return $this->scheme;
4347 else
4349 return null;
4354 * Get the human readable label
4356 * @return string|null
4358 public function get_label()
4360 if ($this->label !== null)
4362 return $this->label;
4364 else
4366 return $this->get_term();
4372 * Content-type sniffing
4374 * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
4376 * This is used since we can't always trust Content-Type headers, and is based
4377 * upon the HTML5 parsing rules.
4380 * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
4382 * @package SimplePie
4383 * @subpackage HTTP
4385 class SimplePie_Content_Type_Sniffer
4388 * File object
4390 * @var SimplePie_File
4392 var $file;
4395 * Create an instance of the class with the input file
4397 * @param SimplePie_Content_Type_Sniffer $file Input file
4399 public function __construct($file)
4401 $this->file = $file;
4405 * Get the Content-Type of the specified file
4407 * @return string Actual Content-Type
4409 public function get_type()
4411 if (isset($this->file->headers['content-type']))
4413 if (!isset($this->file->headers['content-encoding'])
4414 && ($this->file->headers['content-type'] === 'text/plain'
4415 || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
4416 || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
4417 || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
4419 return $this->text_or_binary();
4422 if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
4424 $official = substr($this->file->headers['content-type'], 0, $pos);
4426 else
4428 $official = $this->file->headers['content-type'];
4430 $official = trim(strtolower($official));
4432 if ($official === 'unknown/unknown'
4433 || $official === 'application/unknown')
4435 return $this->unknown();
4437 elseif (substr($official, -4) === '+xml'
4438 || $official === 'text/xml'
4439 || $official === 'application/xml')
4441 return $official;
4443 elseif (substr($official, 0, 6) === 'image/')
4445 if ($return = $this->image())
4447 return $return;
4449 else
4451 return $official;
4454 elseif ($official === 'text/html')
4456 return $this->feed_or_html();
4458 else
4460 return $official;
4463 else
4465 return $this->unknown();
4470 * Sniff text or binary
4472 * @return string Actual Content-Type
4474 public function text_or_binary()
4476 if (substr($this->file->body, 0, 2) === "\xFE\xFF"
4477 || substr($this->file->body, 0, 2) === "\xFF\xFE"
4478 || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
4479 || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
4481 return 'text/plain';
4483 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
4485 return 'application/octect-stream';
4487 else
4489 return 'text/plain';
4494 * Sniff unknown
4496 * @return string Actual Content-Type
4498 public function unknown()
4500 $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
4501 if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
4502 || strtolower(substr($this->file->body, $ws, 5)) === '<html'
4503 || strtolower(substr($this->file->body, $ws, 7)) === '<script')
4505 return 'text/html';
4507 elseif (substr($this->file->body, 0, 5) === '%PDF-')
4509 return 'application/pdf';
4511 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
4513 return 'application/postscript';
4515 elseif (substr($this->file->body, 0, 6) === 'GIF87a'
4516 || substr($this->file->body, 0, 6) === 'GIF89a')
4518 return 'image/gif';
4520 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4522 return 'image/png';
4524 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4526 return 'image/jpeg';
4528 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4530 return 'image/bmp';
4532 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4534 return 'image/vnd.microsoft.icon';
4536 else
4538 return $this->text_or_binary();
4543 * Sniff images
4545 * @return string Actual Content-Type
4547 public function image()
4549 if (substr($this->file->body, 0, 6) === 'GIF87a'
4550 || substr($this->file->body, 0, 6) === 'GIF89a')
4552 return 'image/gif';
4554 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4556 return 'image/png';
4558 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4560 return 'image/jpeg';
4562 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4564 return 'image/bmp';
4566 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4568 return 'image/vnd.microsoft.icon';
4570 else
4572 return false;
4577 * Sniff HTML
4579 * @return string Actual Content-Type
4581 public function feed_or_html()
4583 $len = strlen($this->file->body);
4584 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
4586 while ($pos < $len)
4588 switch ($this->file->body[$pos])
4590 case "\x09":
4591 case "\x0A":
4592 case "\x0D":
4593 case "\x20":
4594 $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
4595 continue 2;
4597 case '<':
4598 $pos++;
4599 break;
4601 default:
4602 return 'text/html';
4605 if (substr($this->file->body, $pos, 3) === '!--')
4607 $pos += 3;
4608 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
4610 $pos += 3;
4612 else
4614 return 'text/html';
4617 elseif (substr($this->file->body, $pos, 1) === '!')
4619 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
4621 $pos++;
4623 else
4625 return 'text/html';
4628 elseif (substr($this->file->body, $pos, 1) === '?')
4630 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
4632 $pos += 2;
4634 else
4636 return 'text/html';
4639 elseif (substr($this->file->body, $pos, 3) === 'rss'
4640 || substr($this->file->body, $pos, 7) === 'rdf:RDF')
4642 return 'application/rss+xml';
4644 elseif (substr($this->file->body, $pos, 4) === 'feed')
4646 return 'application/atom+xml';
4648 else
4650 return 'text/html';
4654 return 'text/html';
4659 * Manages `<media:copyright>` copyright tags as defined in Media RSS
4661 * Used by {@see SimplePie_Enclosure::get_copyright()}
4663 * This class can be overloaded with {@see SimplePie::set_copyright_class()}
4665 * @package SimplePie
4666 * @subpackage API
4668 class SimplePie_Copyright
4671 * Copyright URL
4673 * @var string
4674 * @see get_url()
4676 var $url;
4679 * Attribution
4681 * @var string
4682 * @see get_attribution()
4684 var $label;
4687 * Constructor, used to input the data
4689 * For documentation on all the parameters, see the corresponding
4690 * properties and their accessors
4692 public function __construct($url = null, $label = null)
4694 $this->url = $url;
4695 $this->label = $label;
4699 * String-ified version
4701 * @return string
4703 public function __toString()
4705 // There is no $this->data here
4706 return md5(serialize($this));
4710 * Get the copyright URL
4712 * @return string|null URL to copyright information
4714 public function get_url()
4716 if ($this->url !== null)
4718 return $this->url;
4720 else
4722 return null;
4727 * Get the attribution text
4729 * @return string|null
4731 public function get_attribution()
4733 if ($this->label !== null)
4735 return $this->label;
4737 else
4739 return null;
4745 * SimplePie class.
4747 * Class for backward compatibility.
4749 * @deprecated Use {@see SimplePie} directly
4750 * @package SimplePie
4751 * @subpackage API
4753 class SimplePie_Core extends SimplePie
4759 * Handles `<media:credit>` as defined in Media RSS
4761 * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
4763 * This class can be overloaded with {@see SimplePie::set_credit_class()}
4765 * @package SimplePie
4766 * @subpackage API
4768 class SimplePie_Credit
4771 * Credited role
4773 * @var string
4774 * @see get_role()
4776 var $role;
4779 * Organizational scheme
4781 * @var string
4782 * @see get_scheme()
4784 var $scheme;
4787 * Credited name
4789 * @var string
4790 * @see get_name()
4792 var $name;
4795 * Constructor, used to input the data
4797 * For documentation on all the parameters, see the corresponding
4798 * properties and their accessors
4800 public function __construct($role = null, $scheme = null, $name = null)
4802 $this->role = $role;
4803 $this->scheme = $scheme;
4804 $this->name = $name;
4808 * String-ified version
4810 * @return string
4812 public function __toString()
4814 // There is no $this->data here
4815 return md5(serialize($this));
4819 * Get the role of the person receiving credit
4821 * @return string|null
4823 public function get_role()
4825 if ($this->role !== null)
4827 return $this->role;
4829 else
4831 return null;
4836 * Get the organizational scheme
4838 * @return string|null
4840 public function get_scheme()
4842 if ($this->scheme !== null)
4844 return $this->scheme;
4846 else
4848 return null;
4853 * Get the credited person/entity's name
4855 * @return string|null
4857 public function get_name()
4859 if ($this->name !== null)
4861 return $this->name;
4863 else
4865 return null;
4871 * Decode HTML Entities
4873 * This implements HTML5 as of revision 967 (2007-06-28)
4875 * @deprecated Use DOMDocument instead!
4876 * @package SimplePie
4878 class SimplePie_Decode_HTML_Entities
4881 * Data to be parsed
4883 * @access private
4884 * @var string
4886 var $data = '';
4889 * Currently consumed bytes
4891 * @access private
4892 * @var string
4894 var $consumed = '';
4897 * Position of the current byte being parsed
4899 * @access private
4900 * @var int
4902 var $position = 0;
4905 * Create an instance of the class with the input data
4907 * @access public
4908 * @param string $data Input data
4910 public function __construct($data)
4912 $this->data = $data;
4916 * Parse the input data
4918 * @access public
4919 * @return string Output data
4921 public function parse()
4923 while (($this->position = strpos($this->data, '&', $this->position)) !== false)
4925 $this->consume();
4926 $this->entity();
4927 $this->consumed = '';
4929 return $this->data;
4933 * Consume the next byte
4935 * @access private
4936 * @return mixed The next byte, or false, if there is no more data
4938 public function consume()
4940 if (isset($this->data[$this->position]))
4942 $this->consumed .= $this->data[$this->position];
4943 return $this->data[$this->position++];
4945 else
4947 return false;
4952 * Consume a range of characters
4954 * @access private
4955 * @param string $chars Characters to consume
4956 * @return mixed A series of characters that match the range, or false
4958 public function consume_range($chars)
4960 if ($len = strspn($this->data, $chars, $this->position))
4962 $data = substr($this->data, $this->position, $len);
4963 $this->consumed .= $data;
4964 $this->position += $len;
4965 return $data;
4967 else
4969 return false;
4974 * Unconsume one byte
4976 * @access private
4978 public function unconsume()
4980 $this->consumed = substr($this->consumed, 0, -1);
4981 $this->position--;
4985 * Decode an entity
4987 * @access private
4989 public function entity()
4991 switch ($this->consume())
4993 case "\x09":
4994 case "\x0A":
4995 case "\x0B":
4996 case "\x0B":
4997 case "\x0C":
4998 case "\x20":
4999 case "\x3C":
5000 case "\x26":
5001 case false:
5002 break;
5004 case "\x23":
5005 switch ($this->consume())
5007 case "\x78":
5008 case "\x58":
5009 $range = '0123456789ABCDEFabcdef';
5010 $hex = true;
5011 break;
5013 default:
5014 $range = '0123456789';
5015 $hex = false;
5016 $this->unconsume();
5017 break;
5020 if ($codepoint = $this->consume_range($range))
5022 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");
5024 if ($hex)
5026 $codepoint = hexdec($codepoint);
5028 else
5030 $codepoint = intval($codepoint);
5033 if (isset($windows_1252_specials[$codepoint]))
5035 $replacement = $windows_1252_specials[$codepoint];
5037 else
5039 $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
5042 if (!in_array($this->consume(), array(';', false), true))
5044 $this->unconsume();
5047 $consumed_length = strlen($this->consumed);
5048 $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
5049 $this->position += strlen($replacement) - $consumed_length;
5051 break;
5053 default:
5054 static $entities = array(
5055 'Aacute' => "\xC3\x81",
5056 'aacute' => "\xC3\xA1",
5057 'Aacute;' => "\xC3\x81",
5058 'aacute;' => "\xC3\xA1",
5059 'Acirc' => "\xC3\x82",
5060 'acirc' => "\xC3\xA2",
5061 'Acirc;' => "\xC3\x82",
5062 'acirc;' => "\xC3\xA2",
5063 'acute' => "\xC2\xB4",
5064 'acute;' => "\xC2\xB4",
5065 'AElig' => "\xC3\x86",
5066 'aelig' => "\xC3\xA6",
5067 'AElig;' => "\xC3\x86",
5068 'aelig;' => "\xC3\xA6",
5069 'Agrave' => "\xC3\x80",
5070 'agrave' => "\xC3\xA0",
5071 'Agrave;' => "\xC3\x80",
5072 'agrave;' => "\xC3\xA0",
5073 'alefsym;' => "\xE2\x84\xB5",
5074 'Alpha;' => "\xCE\x91",
5075 'alpha;' => "\xCE\xB1",
5076 'AMP' => "\x26",
5077 'amp' => "\x26",
5078 'AMP;' => "\x26",
5079 'amp;' => "\x26",
5080 'and;' => "\xE2\x88\xA7",
5081 'ang;' => "\xE2\x88\xA0",
5082 'apos;' => "\x27",
5083 'Aring' => "\xC3\x85",
5084 'aring' => "\xC3\xA5",
5085 'Aring;' => "\xC3\x85",
5086 'aring;' => "\xC3\xA5",
5087 'asymp;' => "\xE2\x89\x88",
5088 'Atilde' => "\xC3\x83",
5089 'atilde' => "\xC3\xA3",
5090 'Atilde;' => "\xC3\x83",
5091 'atilde;' => "\xC3\xA3",
5092 'Auml' => "\xC3\x84",
5093 'auml' => "\xC3\xA4",
5094 'Auml;' => "\xC3\x84",
5095 'auml;' => "\xC3\xA4",
5096 'bdquo;' => "\xE2\x80\x9E",
5097 'Beta;' => "\xCE\x92",
5098 'beta;' => "\xCE\xB2",
5099 'brvbar' => "\xC2\xA6",
5100 'brvbar;' => "\xC2\xA6",
5101 'bull;' => "\xE2\x80\xA2",
5102 'cap;' => "\xE2\x88\xA9",
5103 'Ccedil' => "\xC3\x87",
5104 'ccedil' => "\xC3\xA7",
5105 'Ccedil;' => "\xC3\x87",
5106 'ccedil;' => "\xC3\xA7",
5107 'cedil' => "\xC2\xB8",
5108 'cedil;' => "\xC2\xB8",
5109 'cent' => "\xC2\xA2",
5110 'cent;' => "\xC2\xA2",
5111 'Chi;' => "\xCE\xA7",
5112 'chi;' => "\xCF\x87",
5113 'circ;' => "\xCB\x86",
5114 'clubs;' => "\xE2\x99\xA3",
5115 'cong;' => "\xE2\x89\x85",
5116 'COPY' => "\xC2\xA9",
5117 'copy' => "\xC2\xA9",
5118 'COPY;' => "\xC2\xA9",
5119 'copy;' => "\xC2\xA9",
5120 'crarr;' => "\xE2\x86\xB5",
5121 'cup;' => "\xE2\x88\xAA",
5122 'curren' => "\xC2\xA4",
5123 'curren;' => "\xC2\xA4",
5124 'Dagger;' => "\xE2\x80\xA1",
5125 'dagger;' => "\xE2\x80\xA0",
5126 'dArr;' => "\xE2\x87\x93",
5127 'darr;' => "\xE2\x86\x93",
5128 'deg' => "\xC2\xB0",
5129 'deg;' => "\xC2\xB0",
5130 'Delta;' => "\xCE\x94",
5131 'delta;' => "\xCE\xB4",
5132 'diams;' => "\xE2\x99\xA6",
5133 'divide' => "\xC3\xB7",
5134 'divide;' => "\xC3\xB7",
5135 'Eacute' => "\xC3\x89",
5136 'eacute' => "\xC3\xA9",
5137 'Eacute;' => "\xC3\x89",
5138 'eacute;' => "\xC3\xA9",
5139 'Ecirc' => "\xC3\x8A",
5140 'ecirc' => "\xC3\xAA",
5141 'Ecirc;' => "\xC3\x8A",
5142 'ecirc;' => "\xC3\xAA",
5143 'Egrave' => "\xC3\x88",
5144 'egrave' => "\xC3\xA8",
5145 'Egrave;' => "\xC3\x88",
5146 'egrave;' => "\xC3\xA8",
5147 'empty;' => "\xE2\x88\x85",
5148 'emsp;' => "\xE2\x80\x83",
5149 'ensp;' => "\xE2\x80\x82",
5150 'Epsilon;' => "\xCE\x95",
5151 'epsilon;' => "\xCE\xB5",
5152 'equiv;' => "\xE2\x89\xA1",
5153 'Eta;' => "\xCE\x97",
5154 'eta;' => "\xCE\xB7",
5155 'ETH' => "\xC3\x90",
5156 'eth' => "\xC3\xB0",
5157 'ETH;' => "\xC3\x90",
5158 'eth;' => "\xC3\xB0",
5159 'Euml' => "\xC3\x8B",
5160 'euml' => "\xC3\xAB",
5161 'Euml;' => "\xC3\x8B",
5162 'euml;' => "\xC3\xAB",
5163 'euro;' => "\xE2\x82\xAC",
5164 'exist;' => "\xE2\x88\x83",
5165 'fnof;' => "\xC6\x92",
5166 'forall;' => "\xE2\x88\x80",
5167 'frac12' => "\xC2\xBD",
5168 'frac12;' => "\xC2\xBD",
5169 'frac14' => "\xC2\xBC",
5170 'frac14;' => "\xC2\xBC",
5171 'frac34' => "\xC2\xBE",
5172 'frac34;' => "\xC2\xBE",
5173 'frasl;' => "\xE2\x81\x84",
5174 'Gamma;' => "\xCE\x93",
5175 'gamma;' => "\xCE\xB3",
5176 'ge;' => "\xE2\x89\xA5",
5177 'GT' => "\x3E",
5178 'gt' => "\x3E",
5179 'GT;' => "\x3E",
5180 'gt;' => "\x3E",
5181 'hArr;' => "\xE2\x87\x94",
5182 'harr;' => "\xE2\x86\x94",
5183 'hearts;' => "\xE2\x99\xA5",
5184 'hellip;' => "\xE2\x80\xA6",
5185 'Iacute' => "\xC3\x8D",
5186 'iacute' => "\xC3\xAD",
5187 'Iacute;' => "\xC3\x8D",
5188 'iacute;' => "\xC3\xAD",
5189 'Icirc' => "\xC3\x8E",
5190 'icirc' => "\xC3\xAE",
5191 'Icirc;' => "\xC3\x8E",
5192 'icirc;' => "\xC3\xAE",
5193 'iexcl' => "\xC2\xA1",
5194 'iexcl;' => "\xC2\xA1",
5195 'Igrave' => "\xC3\x8C",
5196 'igrave' => "\xC3\xAC",
5197 'Igrave;' => "\xC3\x8C",
5198 'igrave;' => "\xC3\xAC",
5199 'image;' => "\xE2\x84\x91",
5200 'infin;' => "\xE2\x88\x9E",
5201 'int;' => "\xE2\x88\xAB",
5202 'Iota;' => "\xCE\x99",
5203 'iota;' => "\xCE\xB9",
5204 'iquest' => "\xC2\xBF",
5205 'iquest;' => "\xC2\xBF",
5206 'isin;' => "\xE2\x88\x88",
5207 'Iuml' => "\xC3\x8F",
5208 'iuml' => "\xC3\xAF",
5209 'Iuml;' => "\xC3\x8F",
5210 'iuml;' => "\xC3\xAF",
5211 'Kappa;' => "\xCE\x9A",
5212 'kappa;' => "\xCE\xBA",
5213 'Lambda;' => "\xCE\x9B",
5214 'lambda;' => "\xCE\xBB",
5215 'lang;' => "\xE3\x80\x88",
5216 'laquo' => "\xC2\xAB",
5217 'laquo;' => "\xC2\xAB",
5218 'lArr;' => "\xE2\x87\x90",
5219 'larr;' => "\xE2\x86\x90",
5220 'lceil;' => "\xE2\x8C\x88",
5221 'ldquo;' => "\xE2\x80\x9C",
5222 'le;' => "\xE2\x89\xA4",
5223 'lfloor;' => "\xE2\x8C\x8A",
5224 'lowast;' => "\xE2\x88\x97",
5225 'loz;' => "\xE2\x97\x8A",
5226 'lrm;' => "\xE2\x80\x8E",
5227 'lsaquo;' => "\xE2\x80\xB9",
5228 'lsquo;' => "\xE2\x80\x98",
5229 'LT' => "\x3C",
5230 'lt' => "\x3C",
5231 'LT;' => "\x3C",
5232 'lt;' => "\x3C",
5233 'macr' => "\xC2\xAF",
5234 'macr;' => "\xC2\xAF",
5235 'mdash;' => "\xE2\x80\x94",
5236 'micro' => "\xC2\xB5",
5237 'micro;' => "\xC2\xB5",
5238 'middot' => "\xC2\xB7",
5239 'middot;' => "\xC2\xB7",
5240 'minus;' => "\xE2\x88\x92",
5241 'Mu;' => "\xCE\x9C",
5242 'mu;' => "\xCE\xBC",
5243 'nabla;' => "\xE2\x88\x87",
5244 'nbsp' => "\xC2\xA0",
5245 'nbsp;' => "\xC2\xA0",
5246 'ndash;' => "\xE2\x80\x93",
5247 'ne;' => "\xE2\x89\xA0",
5248 'ni;' => "\xE2\x88\x8B",
5249 'not' => "\xC2\xAC",
5250 'not;' => "\xC2\xAC",
5251 'notin;' => "\xE2\x88\x89",
5252 'nsub;' => "\xE2\x8A\x84",
5253 'Ntilde' => "\xC3\x91",
5254 'ntilde' => "\xC3\xB1",
5255 'Ntilde;' => "\xC3\x91",
5256 'ntilde;' => "\xC3\xB1",
5257 'Nu;' => "\xCE\x9D",
5258 'nu;' => "\xCE\xBD",
5259 'Oacute' => "\xC3\x93",
5260 'oacute' => "\xC3\xB3",
5261 'Oacute;' => "\xC3\x93",
5262 'oacute;' => "\xC3\xB3",
5263 'Ocirc' => "\xC3\x94",
5264 'ocirc' => "\xC3\xB4",
5265 'Ocirc;' => "\xC3\x94",
5266 'ocirc;' => "\xC3\xB4",
5267 'OElig;' => "\xC5\x92",
5268 'oelig;' => "\xC5\x93",
5269 'Ograve' => "\xC3\x92",
5270 'ograve' => "\xC3\xB2",
5271 'Ograve;' => "\xC3\x92",
5272 'ograve;' => "\xC3\xB2",
5273 'oline;' => "\xE2\x80\xBE",
5274 'Omega;' => "\xCE\xA9",
5275 'omega;' => "\xCF\x89",
5276 'Omicron;' => "\xCE\x9F",
5277 'omicron;' => "\xCE\xBF",
5278 'oplus;' => "\xE2\x8A\x95",
5279 'or;' => "\xE2\x88\xA8",
5280 'ordf' => "\xC2\xAA",
5281 'ordf;' => "\xC2\xAA",
5282 'ordm' => "\xC2\xBA",
5283 'ordm;' => "\xC2\xBA",
5284 'Oslash' => "\xC3\x98",
5285 'oslash' => "\xC3\xB8",
5286 'Oslash;' => "\xC3\x98",
5287 'oslash;' => "\xC3\xB8",
5288 'Otilde' => "\xC3\x95",
5289 'otilde' => "\xC3\xB5",
5290 'Otilde;' => "\xC3\x95",
5291 'otilde;' => "\xC3\xB5",
5292 'otimes;' => "\xE2\x8A\x97",
5293 'Ouml' => "\xC3\x96",
5294 'ouml' => "\xC3\xB6",
5295 'Ouml;' => "\xC3\x96",
5296 'ouml;' => "\xC3\xB6",
5297 'para' => "\xC2\xB6",
5298 'para;' => "\xC2\xB6",
5299 'part;' => "\xE2\x88\x82",
5300 'permil;' => "\xE2\x80\xB0",
5301 'perp;' => "\xE2\x8A\xA5",
5302 'Phi;' => "\xCE\xA6",
5303 'phi;' => "\xCF\x86",
5304 'Pi;' => "\xCE\xA0",
5305 'pi;' => "\xCF\x80",
5306 'piv;' => "\xCF\x96",
5307 'plusmn' => "\xC2\xB1",
5308 'plusmn;' => "\xC2\xB1",
5309 'pound' => "\xC2\xA3",
5310 'pound;' => "\xC2\xA3",
5311 'Prime;' => "\xE2\x80\xB3",
5312 'prime;' => "\xE2\x80\xB2",
5313 'prod;' => "\xE2\x88\x8F",
5314 'prop;' => "\xE2\x88\x9D",
5315 'Psi;' => "\xCE\xA8",
5316 'psi;' => "\xCF\x88",
5317 'QUOT' => "\x22",
5318 'quot' => "\x22",
5319 'QUOT;' => "\x22",
5320 'quot;' => "\x22",
5321 'radic;' => "\xE2\x88\x9A",
5322 'rang;' => "\xE3\x80\x89",
5323 'raquo' => "\xC2\xBB",
5324 'raquo;' => "\xC2\xBB",
5325 'rArr;' => "\xE2\x87\x92",
5326 'rarr;' => "\xE2\x86\x92",
5327 'rceil;' => "\xE2\x8C\x89",
5328 'rdquo;' => "\xE2\x80\x9D",
5329 'real;' => "\xE2\x84\x9C",
5330 'REG' => "\xC2\xAE",
5331 'reg' => "\xC2\xAE",
5332 'REG;' => "\xC2\xAE",
5333 'reg;' => "\xC2\xAE",
5334 'rfloor;' => "\xE2\x8C\x8B",
5335 'Rho;' => "\xCE\xA1",
5336 'rho;' => "\xCF\x81",
5337 'rlm;' => "\xE2\x80\x8F",
5338 'rsaquo;' => "\xE2\x80\xBA",
5339 'rsquo;' => "\xE2\x80\x99",
5340 'sbquo;' => "\xE2\x80\x9A",
5341 'Scaron;' => "\xC5\xA0",
5342 'scaron;' => "\xC5\xA1",
5343 'sdot;' => "\xE2\x8B\x85",
5344 'sect' => "\xC2\xA7",
5345 'sect;' => "\xC2\xA7",
5346 'shy' => "\xC2\xAD",
5347 'shy;' => "\xC2\xAD",
5348 'Sigma;' => "\xCE\xA3",
5349 'sigma;' => "\xCF\x83",
5350 'sigmaf;' => "\xCF\x82",
5351 'sim;' => "\xE2\x88\xBC",
5352 'spades;' => "\xE2\x99\xA0",
5353 'sub;' => "\xE2\x8A\x82",
5354 'sube;' => "\xE2\x8A\x86",
5355 'sum;' => "\xE2\x88\x91",
5356 'sup;' => "\xE2\x8A\x83",
5357 'sup1' => "\xC2\xB9",
5358 'sup1;' => "\xC2\xB9",
5359 'sup2' => "\xC2\xB2",
5360 'sup2;' => "\xC2\xB2",
5361 'sup3' => "\xC2\xB3",
5362 'sup3;' => "\xC2\xB3",
5363 'supe;' => "\xE2\x8A\x87",
5364 'szlig' => "\xC3\x9F",
5365 'szlig;' => "\xC3\x9F",
5366 'Tau;' => "\xCE\xA4",
5367 'tau;' => "\xCF\x84",
5368 'there4;' => "\xE2\x88\xB4",
5369 'Theta;' => "\xCE\x98",
5370 'theta;' => "\xCE\xB8",
5371 'thetasym;' => "\xCF\x91",
5372 'thinsp;' => "\xE2\x80\x89",
5373 'THORN' => "\xC3\x9E",
5374 'thorn' => "\xC3\xBE",
5375 'THORN;' => "\xC3\x9E",
5376 'thorn;' => "\xC3\xBE",
5377 'tilde;' => "\xCB\x9C",
5378 'times' => "\xC3\x97",
5379 'times;' => "\xC3\x97",
5380 'TRADE;' => "\xE2\x84\xA2",
5381 'trade;' => "\xE2\x84\xA2",
5382 'Uacute' => "\xC3\x9A",
5383 'uacute' => "\xC3\xBA",
5384 'Uacute;' => "\xC3\x9A",
5385 'uacute;' => "\xC3\xBA",
5386 'uArr;' => "\xE2\x87\x91",
5387 'uarr;' => "\xE2\x86\x91",
5388 'Ucirc' => "\xC3\x9B",
5389 'ucirc' => "\xC3\xBB",
5390 'Ucirc;' => "\xC3\x9B",
5391 'ucirc;' => "\xC3\xBB",
5392 'Ugrave' => "\xC3\x99",
5393 'ugrave' => "\xC3\xB9",
5394 'Ugrave;' => "\xC3\x99",
5395 'ugrave;' => "\xC3\xB9",
5396 'uml' => "\xC2\xA8",
5397 'uml;' => "\xC2\xA8",
5398 'upsih;' => "\xCF\x92",
5399 'Upsilon;' => "\xCE\xA5",
5400 'upsilon;' => "\xCF\x85",
5401 'Uuml' => "\xC3\x9C",
5402 'uuml' => "\xC3\xBC",
5403 'Uuml;' => "\xC3\x9C",
5404 'uuml;' => "\xC3\xBC",
5405 'weierp;' => "\xE2\x84\x98",
5406 'Xi;' => "\xCE\x9E",
5407 'xi;' => "\xCE\xBE",
5408 'Yacute' => "\xC3\x9D",
5409 'yacute' => "\xC3\xBD",
5410 'Yacute;' => "\xC3\x9D",
5411 'yacute;' => "\xC3\xBD",
5412 'yen' => "\xC2\xA5",
5413 'yen;' => "\xC2\xA5",
5414 'yuml' => "\xC3\xBF",
5415 'Yuml;' => "\xC5\xB8",
5416 'yuml;' => "\xC3\xBF",
5417 'Zeta;' => "\xCE\x96",
5418 'zeta;' => "\xCE\xB6",
5419 'zwj;' => "\xE2\x80\x8D",
5420 'zwnj;' => "\xE2\x80\x8C"
5423 for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
5425 $consumed = substr($this->consumed, 1);
5426 if (isset($entities[$consumed]))
5428 $match = $consumed;
5432 if ($match !== null)
5434 $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
5435 $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
5437 break;
5443 * Handles everything related to enclosures (including Media RSS and iTunes RSS)
5445 * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
5447 * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
5449 * @package SimplePie
5450 * @subpackage API
5452 class SimplePie_Enclosure
5455 * @var string
5456 * @see get_bitrate()
5458 var $bitrate;
5461 * @var array
5462 * @see get_captions()
5464 var $captions;
5467 * @var array
5468 * @see get_categories()
5470 var $categories;
5473 * @var int
5474 * @see get_channels()
5476 var $channels;
5479 * @var SimplePie_Copyright
5480 * @see get_copyright()
5482 var $copyright;
5485 * @var array
5486 * @see get_credits()
5488 var $credits;
5491 * @var string
5492 * @see get_description()
5494 var $description;
5497 * @var int
5498 * @see get_duration()
5500 var $duration;
5503 * @var string
5504 * @see get_expression()
5506 var $expression;
5509 * @var string
5510 * @see get_framerate()
5512 var $framerate;
5515 * @var string
5516 * @see get_handler()
5518 var $handler;
5521 * @var array
5522 * @see get_hashes()
5524 var $hashes;
5527 * @var string
5528 * @see get_height()
5530 var $height;
5533 * @deprecated
5534 * @var null
5536 var $javascript;
5539 * @var array
5540 * @see get_keywords()
5542 var $keywords;
5545 * @var string
5546 * @see get_language()
5548 var $lang;
5551 * @var string
5552 * @see get_length()
5554 var $length;
5557 * @var string
5558 * @see get_link()
5560 var $link;
5563 * @var string
5564 * @see get_medium()
5566 var $medium;
5569 * @var string
5570 * @see get_player()
5572 var $player;
5575 * @var array
5576 * @see get_ratings()
5578 var $ratings;
5581 * @var array
5582 * @see get_restrictions()
5584 var $restrictions;
5587 * @var string
5588 * @see get_sampling_rate()
5590 var $samplingrate;
5593 * @var array
5594 * @see get_thumbnails()
5596 var $thumbnails;
5599 * @var string
5600 * @see get_title()
5602 var $title;
5605 * @var string
5606 * @see get_type()
5608 var $type;
5611 * @var string
5612 * @see get_width()
5614 var $width;
5617 * Constructor, used to input the data
5619 * For documentation on all the parameters, see the corresponding
5620 * properties and their accessors
5622 * @uses idna_convert If available, this will convert an IDN
5624 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)
5626 $this->bitrate = $bitrate;
5627 $this->captions = $captions;
5628 $this->categories = $categories;
5629 $this->channels = $channels;
5630 $this->copyright = $copyright;
5631 $this->credits = $credits;
5632 $this->description = $description;
5633 $this->duration = $duration;
5634 $this->expression = $expression;
5635 $this->framerate = $framerate;
5636 $this->hashes = $hashes;
5637 $this->height = $height;
5638 $this->keywords = $keywords;
5639 $this->lang = $lang;
5640 $this->length = $length;
5641 $this->link = $link;
5642 $this->medium = $medium;
5643 $this->player = $player;
5644 $this->ratings = $ratings;
5645 $this->restrictions = $restrictions;
5646 $this->samplingrate = $samplingrate;
5647 $this->thumbnails = $thumbnails;
5648 $this->title = $title;
5649 $this->type = $type;
5650 $this->width = $width;
5652 if (class_exists('idna_convert'))
5654 $idn = new idna_convert();
5655 $parsed = SimplePie_Misc::parse_url($link);
5656 $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
5658 $this->handler = $this->get_handler(); // Needs to load last
5662 * String-ified version
5664 * @return string
5666 public function __toString()
5668 // There is no $this->data here
5669 return md5(serialize($this));
5673 * Get the bitrate
5675 * @return string|null
5677 public function get_bitrate()
5679 if ($this->bitrate !== null)
5681 return $this->bitrate;
5683 else
5685 return null;
5690 * Get a single caption
5692 * @param int $key
5693 * @return SimplePie_Caption|null
5695 public function get_caption($key = 0)
5697 $captions = $this->get_captions();
5698 if (isset($captions[$key]))
5700 return $captions[$key];
5702 else
5704 return null;
5709 * Get all captions
5711 * @return array|null Array of {@see SimplePie_Caption} objects
5713 public function get_captions()
5715 if ($this->captions !== null)
5717 return $this->captions;
5719 else
5721 return null;
5726 * Get a single category
5728 * @param int $key
5729 * @return SimplePie_Category|null
5731 public function get_category($key = 0)
5733 $categories = $this->get_categories();
5734 if (isset($categories[$key]))
5736 return $categories[$key];
5738 else
5740 return null;
5745 * Get all categories
5747 * @return array|null Array of {@see SimplePie_Category} objects
5749 public function get_categories()
5751 if ($this->categories !== null)
5753 return $this->categories;
5755 else
5757 return null;
5762 * Get the number of audio channels
5764 * @return int|null
5766 public function get_channels()
5768 if ($this->channels !== null)
5770 return $this->channels;
5772 else
5774 return null;
5779 * Get the copyright information
5781 * @return SimplePie_Copyright|null
5783 public function get_copyright()
5785 if ($this->copyright !== null)
5787 return $this->copyright;
5789 else
5791 return null;
5796 * Get a single credit
5798 * @param int $key
5799 * @return SimplePie_Credit|null
5801 public function get_credit($key = 0)
5803 $credits = $this->get_credits();
5804 if (isset($credits[$key]))
5806 return $credits[$key];
5808 else
5810 return null;
5815 * Get all credits
5817 * @return array|null Array of {@see SimplePie_Credit} objects
5819 public function get_credits()
5821 if ($this->credits !== null)
5823 return $this->credits;
5825 else
5827 return null;
5832 * Get the description of the enclosure
5834 * @return string|null
5836 public function get_description()
5838 if ($this->description !== null)
5840 return $this->description;
5842 else
5844 return null;
5849 * Get the duration of the enclosure
5851 * @param string $convert Convert seconds into hh:mm:ss
5852 * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
5854 public function get_duration($convert = false)
5856 if ($this->duration !== null)
5858 if ($convert)
5860 $time = SimplePie_Misc::time_hms($this->duration);
5861 return $time;
5863 else
5865 return $this->duration;
5868 else
5870 return null;
5875 * Get the expression
5877 * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
5879 public function get_expression()
5881 if ($this->expression !== null)
5883 return $this->expression;
5885 else
5887 return 'full';
5892 * Get the file extension
5894 * @return string|null
5896 public function get_extension()
5898 if ($this->link !== null)
5900 $url = SimplePie_Misc::parse_url($this->link);
5901 if ($url['path'] !== '')
5903 return pathinfo($url['path'], PATHINFO_EXTENSION);
5906 return null;
5910 * Get the framerate (in frames-per-second)
5912 * @return string|null
5914 public function get_framerate()
5916 if ($this->framerate !== null)
5918 return $this->framerate;
5920 else
5922 return null;
5927 * Get the preferred handler
5929 * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
5931 public function get_handler()
5933 return $this->get_real_type(true);
5937 * Get a single hash
5939 * @link http://www.rssboard.org/media-rss#media-hash
5940 * @param int $key
5941 * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
5943 public function get_hash($key = 0)
5945 $hashes = $this->get_hashes();
5946 if (isset($hashes[$key]))
5948 return $hashes[$key];
5950 else
5952 return null;
5957 * Get all credits
5959 * @return array|null Array of strings, see {@see get_hash()}
5961 public function get_hashes()
5963 if ($this->hashes !== null)
5965 return $this->hashes;
5967 else
5969 return null;
5974 * Get the height
5976 * @return string|null
5978 public function get_height()
5980 if ($this->height !== null)
5982 return $this->height;
5984 else
5986 return null;
5991 * Get the language
5993 * @link http://tools.ietf.org/html/rfc3066
5994 * @return string|null Language code as per RFC 3066
5996 public function get_language()
5998 if ($this->lang !== null)
6000 return $this->lang;
6002 else
6004 return null;
6009 * Get a single keyword
6011 * @param int $key
6012 * @return string|null
6014 public function get_keyword($key = 0)
6016 $keywords = $this->get_keywords();
6017 if (isset($keywords[$key]))
6019 return $keywords[$key];
6021 else
6023 return null;
6028 * Get all keywords
6030 * @return array|null Array of strings
6032 public function get_keywords()
6034 if ($this->keywords !== null)
6036 return $this->keywords;
6038 else
6040 return null;
6045 * Get length
6047 * @return float Length in bytes
6049 public function get_length()
6051 if ($this->length !== null)
6053 return $this->length;
6055 else
6057 return null;
6062 * Get the URL
6064 * @return string|null
6066 public function get_link()
6068 if ($this->link !== null)
6070 return urldecode($this->link);
6072 else
6074 return null;
6079 * Get the medium
6081 * @link http://www.rssboard.org/media-rss#media-content
6082 * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
6084 public function get_medium()
6086 if ($this->medium !== null)
6088 return $this->medium;
6090 else
6092 return null;
6097 * Get the player URL
6099 * Typically the same as {@see get_permalink()}
6100 * @return string|null Player URL
6102 public function get_player()
6104 if ($this->player !== null)
6106 return $this->player;
6108 else
6110 return null;
6115 * Get a single rating
6117 * @param int $key
6118 * @return SimplePie_Rating|null
6120 public function get_rating($key = 0)
6122 $ratings = $this->get_ratings();
6123 if (isset($ratings[$key]))
6125 return $ratings[$key];
6127 else
6129 return null;
6134 * Get all ratings
6136 * @return array|null Array of {@see SimplePie_Rating} objects
6138 public function get_ratings()
6140 if ($this->ratings !== null)
6142 return $this->ratings;
6144 else
6146 return null;
6151 * Get a single restriction
6153 * @param int $key
6154 * @return SimplePie_Restriction|null
6156 public function get_restriction($key = 0)
6158 $restrictions = $this->get_restrictions();
6159 if (isset($restrictions[$key]))
6161 return $restrictions[$key];
6163 else
6165 return null;
6170 * Get all restrictions
6172 * @return array|null Array of {@see SimplePie_Restriction} objects
6174 public function get_restrictions()
6176 if ($this->restrictions !== null)
6178 return $this->restrictions;
6180 else
6182 return null;
6187 * Get the sampling rate (in kHz)
6189 * @return string|null
6191 public function get_sampling_rate()
6193 if ($this->samplingrate !== null)
6195 return $this->samplingrate;
6197 else
6199 return null;
6204 * Get the file size (in MiB)
6206 * @return float|null File size in mebibytes (1048 bytes)
6208 public function get_size()
6210 $length = $this->get_length();
6211 if ($length !== null)
6213 return round($length/1048576, 2);
6215 else
6217 return null;
6222 * Get a single thumbnail
6224 * @param int $key
6225 * @return string|null Thumbnail URL
6227 public function get_thumbnail($key = 0)
6229 $thumbnails = $this->get_thumbnails();
6230 if (isset($thumbnails[$key]))
6232 return $thumbnails[$key];
6234 else
6236 return null;
6241 * Get all thumbnails
6243 * @return array|null Array of thumbnail URLs
6245 public function get_thumbnails()
6247 if ($this->thumbnails !== null)
6249 return $this->thumbnails;
6251 else
6253 return null;
6258 * Get the title
6260 * @return string|null
6262 public function get_title()
6264 if ($this->title !== null)
6266 return $this->title;
6268 else
6270 return null;
6275 * Get mimetype of the enclosure
6277 * @see get_real_type()
6278 * @return string|null MIME type
6280 public function get_type()
6282 if ($this->type !== null)
6284 return $this->type;
6286 else
6288 return null;
6293 * Get the width
6295 * @return string|null
6297 public function get_width()
6299 if ($this->width !== null)
6301 return $this->width;
6303 else
6305 return null;
6310 * Embed the enclosure using `<embed>`
6312 * @deprecated Use the second parameter to {@see embed} instead
6314 * @param array|string $options See first paramter to {@see embed}
6315 * @return string HTML string to output
6317 public function native_embed($options='')
6319 return $this->embed($options, true);
6323 * Embed the enclosure using Javascript
6325 * `$options` is an array or comma-separated key:value string, with the
6326 * following properties:
6328 * - `alt` (string): Alternate content for when an end-user does not have
6329 * the appropriate handler installed or when a file type is
6330 * unsupported. Can be any text or HTML. Defaults to blank.
6331 * - `altclass` (string): If a file type is unsupported, the end-user will
6332 * see the alt text (above) linked directly to the content. That link
6333 * will have this value as its class name. Defaults to blank.
6334 * - `audio` (string): This is an image that should be used as a
6335 * placeholder for audio files before they're loaded (QuickTime-only).
6336 * Can be any relative or absolute URL. Defaults to blank.
6337 * - `bgcolor` (string): The background color for the media, if not
6338 * already transparent. Defaults to `#ffffff`.
6339 * - `height` (integer): The height of the embedded media. Accepts any
6340 * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
6341 * and it is recommended that you use this default.
6342 * - `loop` (boolean): Do you want the media to loop when its done?
6343 * Defaults to `false`.
6344 * - `mediaplayer` (string): The location of the included
6345 * `mediaplayer.swf` file. This allows for the playback of Flash Video
6346 * (`.flv`) files, and is the default handler for non-Odeo MP3's.
6347 * Defaults to blank.
6348 * - `video` (string): This is an image that should be used as a
6349 * placeholder for video files before they're loaded (QuickTime-only).
6350 * Can be any relative or absolute URL. Defaults to blank.
6351 * - `width` (integer): The width of the embedded media. Accepts any
6352 * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
6353 * and it is recommended that you use this default.
6354 * - `widescreen` (boolean): Is the enclosure widescreen or standard?
6355 * This applies only to video enclosures, and will automatically resize
6356 * the content appropriately. Defaults to `false`, implying 4:3 mode.
6358 * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
6359 * will default to 480x360 video resolution. Widescreen (16:9) mode with
6360 * `width` and `height` set to `auto` will default to 480x270 video resolution.
6362 * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
6363 * @param array|string $options Comma-separated key:value list, or array
6364 * @param bool $native Use `<embed>`
6365 * @return string HTML string to output
6367 public function embed($options = '', $native = false)
6369 // Set up defaults
6370 $audio = '';
6371 $video = '';
6372 $alt = '';
6373 $altclass = '';
6374 $loop = 'false';
6375 $width = 'auto';
6376 $height = 'auto';
6377 $bgcolor = '#ffffff';
6378 $mediaplayer = '';
6379 $widescreen = false;
6380 $handler = $this->get_handler();
6381 $type = $this->get_real_type();
6383 // Process options and reassign values as necessary
6384 if (is_array($options))
6386 extract($options);
6388 else
6390 $options = explode(',', $options);
6391 foreach($options as $option)
6393 $opt = explode(':', $option, 2);
6394 if (isset($opt[0], $opt[1]))
6396 $opt[0] = trim($opt[0]);
6397 $opt[1] = trim($opt[1]);
6398 switch ($opt[0])
6400 case 'audio':
6401 $audio = $opt[1];
6402 break;
6404 case 'video':
6405 $video = $opt[1];
6406 break;
6408 case 'alt':
6409 $alt = $opt[1];
6410 break;
6412 case 'altclass':
6413 $altclass = $opt[1];
6414 break;
6416 case 'loop':
6417 $loop = $opt[1];
6418 break;
6420 case 'width':
6421 $width = $opt[1];
6422 break;
6424 case 'height':
6425 $height = $opt[1];
6426 break;
6428 case 'bgcolor':
6429 $bgcolor = $opt[1];
6430 break;
6432 case 'mediaplayer':
6433 $mediaplayer = $opt[1];
6434 break;
6436 case 'widescreen':
6437 $widescreen = $opt[1];
6438 break;
6444 $mime = explode('/', $type, 2);
6445 $mime = $mime[0];
6447 // Process values for 'auto'
6448 if ($width === 'auto')
6450 if ($mime === 'video')
6452 if ($height === 'auto')
6454 $width = 480;
6456 elseif ($widescreen)
6458 $width = round((intval($height)/9)*16);
6460 else
6462 $width = round((intval($height)/3)*4);
6465 else
6467 $width = '100%';
6471 if ($height === 'auto')
6473 if ($mime === 'audio')
6475 $height = 0;
6477 elseif ($mime === 'video')
6479 if ($width === 'auto')
6481 if ($widescreen)
6483 $height = 270;
6485 else
6487 $height = 360;
6490 elseif ($widescreen)
6492 $height = round((intval($width)/16)*9);
6494 else
6496 $height = round((intval($width)/4)*3);
6499 else
6501 $height = 376;
6504 elseif ($mime === 'audio')
6506 $height = 0;
6509 // Set proper placeholder value
6510 if ($mime === 'audio')
6512 $placeholder = $audio;
6514 elseif ($mime === 'video')
6516 $placeholder = $video;
6519 $embed = '';
6521 // Flash
6522 if ($handler === 'flash')
6524 if ($native)
6526 $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>";
6528 else
6530 $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
6534 // Flash Media Player file types.
6535 // Preferred handler for MP3 file types.
6536 elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
6538 $height += 20;
6539 if ($native)
6541 $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>";
6543 else
6545 $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
6549 // QuickTime 7 file types. Need to test with QuickTime 6.
6550 // Only handle MP3's if the Flash Media Player is not present.
6551 elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
6553 $height += 16;
6554 if ($native)
6556 if ($placeholder !== '')
6558 $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>";
6560 else
6562 $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>";
6565 else
6567 $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
6571 // Windows Media
6572 elseif ($handler === 'wmedia')
6574 $height += 45;
6575 if ($native)
6577 $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>";
6579 else
6581 $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
6585 // Everything else
6586 else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
6588 return $embed;
6592 * Get the real media type
6594 * Often, feeds lie to us, necessitating a bit of deeper inspection. This
6595 * converts types to their canonical representations based on the file
6596 * extension
6598 * @see get_type()
6599 * @param bool $find_handler Internal use only, use {@see get_handler()} instead
6600 * @return string MIME type
6602 public function get_real_type($find_handler = false)
6604 // Mime-types by handler.
6605 $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
6606 $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
6607 $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
6608 $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
6609 $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
6611 if ($this->get_type() !== null)
6613 $type = strtolower($this->type);
6615 else
6617 $type = null;
6620 // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
6621 if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
6623 switch (strtolower($this->get_extension()))
6625 // Audio mime-types
6626 case 'aac':
6627 case 'adts':
6628 $type = 'audio/acc';
6629 break;
6631 case 'aif':
6632 case 'aifc':
6633 case 'aiff':
6634 case 'cdda':
6635 $type = 'audio/aiff';
6636 break;
6638 case 'bwf':
6639 $type = 'audio/wav';
6640 break;
6642 case 'kar':
6643 case 'mid':
6644 case 'midi':
6645 case 'smf':
6646 $type = 'audio/midi';
6647 break;
6649 case 'm4a':
6650 $type = 'audio/x-m4a';
6651 break;
6653 case 'mp3':
6654 case 'swa':
6655 $type = 'audio/mp3';
6656 break;
6658 case 'wav':
6659 $type = 'audio/wav';
6660 break;
6662 case 'wax':
6663 $type = 'audio/x-ms-wax';
6664 break;
6666 case 'wma':
6667 $type = 'audio/x-ms-wma';
6668 break;
6670 // Video mime-types
6671 case '3gp':
6672 case '3gpp':
6673 $type = 'video/3gpp';
6674 break;
6676 case '3g2':
6677 case '3gp2':
6678 $type = 'video/3gpp2';
6679 break;
6681 case 'asf':
6682 $type = 'video/x-ms-asf';
6683 break;
6685 case 'flv':
6686 $type = 'video/x-flv';
6687 break;
6689 case 'm1a':
6690 case 'm1s':
6691 case 'm1v':
6692 case 'm15':
6693 case 'm75':
6694 case 'mp2':
6695 case 'mpa':
6696 case 'mpeg':
6697 case 'mpg':
6698 case 'mpm':
6699 case 'mpv':
6700 $type = 'video/mpeg';
6701 break;
6703 case 'm4v':
6704 $type = 'video/x-m4v';
6705 break;
6707 case 'mov':
6708 case 'qt':
6709 $type = 'video/quicktime';
6710 break;
6712 case 'mp4':
6713 case 'mpg4':
6714 $type = 'video/mp4';
6715 break;
6717 case 'sdv':
6718 $type = 'video/sd-video';
6719 break;
6721 case 'wm':
6722 $type = 'video/x-ms-wm';
6723 break;
6725 case 'wmv':
6726 $type = 'video/x-ms-wmv';
6727 break;
6729 case 'wvx':
6730 $type = 'video/x-ms-wvx';
6731 break;
6733 // Flash mime-types
6734 case 'spl':
6735 $type = 'application/futuresplash';
6736 break;
6738 case 'swf':
6739 $type = 'application/x-shockwave-flash';
6740 break;
6744 if ($find_handler)
6746 if (in_array($type, $types_flash))
6748 return 'flash';
6750 elseif (in_array($type, $types_fmedia))
6752 return 'fmedia';
6754 elseif (in_array($type, $types_quicktime))
6756 return 'quicktime';
6758 elseif (in_array($type, $types_wmedia))
6760 return 'wmedia';
6762 elseif (in_array($type, $types_mp3))
6764 return 'mp3';
6766 else
6768 return null;
6771 else
6773 return $type;
6779 * General SimplePie exception class
6781 * @package SimplePie
6783 class SimplePie_Exception extends Exception
6788 * Used for fetching remote files and reading local files
6790 * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
6792 * This class can be overloaded with {@see SimplePie::set_file_class()}
6794 * @package SimplePie
6795 * @subpackage HTTP
6796 * @todo Move to properly supporting RFC2616 (HTTP/1.1)
6798 class SimplePie_File
6800 var $url;
6801 var $useragent;
6802 var $success = true;
6803 var $headers = array();
6804 var $body;
6805 var $status_code;
6806 var $redirects = 0;
6807 var $error;
6808 var $method = SIMPLEPIE_FILE_SOURCE_NONE;
6810 public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
6812 if (class_exists('idna_convert'))
6814 $idn = new idna_convert();
6815 $parsed = SimplePie_Misc::parse_url($url);
6816 $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
6818 $this->url = $url;
6819 $this->useragent = $useragent;
6820 if (preg_match('/^http(s)?:\/\//i', $url))
6822 if ($useragent === null)
6824 $useragent = ini_get('user_agent');
6825 $this->useragent = $useragent;
6827 if (!is_array($headers))
6829 $headers = array();
6831 if (!$force_fsockopen && function_exists('curl_exec'))
6833 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
6834 $fp = curl_init();
6835 $headers2 = array();
6836 foreach ($headers as $key => $value)
6838 $headers2[] = "$key: $value";
6840 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
6842 curl_setopt($fp, CURLOPT_ENCODING, '');
6844 curl_setopt($fp, CURLOPT_URL, $url);
6845 curl_setopt($fp, CURLOPT_HEADER, 1);
6846 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
6847 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
6848 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
6849 curl_setopt($fp, CURLOPT_REFERER, $url);
6850 curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
6851 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
6852 if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
6854 curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
6855 curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
6858 $this->headers = curl_exec($fp);
6859 if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
6861 curl_setopt($fp, CURLOPT_ENCODING, 'none');
6862 $this->headers = curl_exec($fp);
6864 if (curl_errno($fp))
6866 $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
6867 $this->success = false;
6869 else
6871 $info = curl_getinfo($fp);
6872 curl_close($fp);
6873 $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
6874 $this->headers = array_pop($this->headers);
6875 $parser = new SimplePie_HTTP_Parser($this->headers);
6876 if ($parser->parse())
6878 $this->headers = $parser->headers;
6879 $this->body = $parser->body;
6880 $this->status_code = $parser->status_code;
6881 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)
6883 $this->redirects++;
6884 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6885 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6890 else
6892 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
6893 $url_parts = parse_url($url);
6894 $socket_host = $url_parts['host'];
6895 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
6897 $socket_host = "ssl://$url_parts[host]";
6898 $url_parts['port'] = 443;
6900 if (!isset($url_parts['port']))
6902 $url_parts['port'] = 80;
6904 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
6905 if (!$fp)
6907 $this->error = 'fsockopen error: ' . $errstr;
6908 $this->success = false;
6910 else
6912 stream_set_timeout($fp, $timeout);
6913 if (isset($url_parts['path']))
6915 if (isset($url_parts['query']))
6917 $get = "$url_parts[path]?$url_parts[query]";
6919 else
6921 $get = $url_parts['path'];
6924 else
6926 $get = '/';
6928 $out = "GET $get HTTP/1.1\r\n";
6929 $out .= "Host: $url_parts[host]\r\n";
6930 $out .= "User-Agent: $useragent\r\n";
6931 if (extension_loaded('zlib'))
6933 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
6936 if (isset($url_parts['user']) && isset($url_parts['pass']))
6938 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
6940 foreach ($headers as $key => $value)
6942 $out .= "$key: $value\r\n";
6944 $out .= "Connection: Close\r\n\r\n";
6945 fwrite($fp, $out);
6947 $info = stream_get_meta_data($fp);
6949 $this->headers = '';
6950 while (!$info['eof'] && !$info['timed_out'])
6952 $this->headers .= fread($fp, 1160);
6953 $info = stream_get_meta_data($fp);
6955 if (!$info['timed_out'])
6957 $parser = new SimplePie_HTTP_Parser($this->headers);
6958 if ($parser->parse())
6960 $this->headers = $parser->headers;
6961 $this->body = $parser->body;
6962 $this->status_code = $parser->status_code;
6963 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)
6965 $this->redirects++;
6966 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6967 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6969 if (isset($this->headers['content-encoding']))
6971 // Hey, we act dumb elsewhere, so let's do that here too
6972 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
6974 case 'gzip':
6975 case 'x-gzip':
6976 $decoder = new SimplePie_gzdecode($this->body);
6977 if (!$decoder->parse())
6979 $this->error = 'Unable to decode HTTP "gzip" stream';
6980 $this->success = false;
6982 else
6984 $this->body = $decoder->data;
6986 break;
6988 case 'deflate':
6989 if (($decompressed = gzinflate($this->body)) !== false)
6991 $this->body = $decompressed;
6993 else if (($decompressed = gzuncompress($this->body)) !== false)
6995 $this->body = $decompressed;
6997 else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
6999 $this->body = $decompressed;
7001 else
7003 $this->error = 'Unable to decode HTTP "deflate" stream';
7004 $this->success = false;
7006 break;
7008 default:
7009 $this->error = 'Unknown content coding';
7010 $this->success = false;
7015 else
7017 $this->error = 'fsocket timed out';
7018 $this->success = false;
7020 fclose($fp);
7024 else
7026 $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
7027 if (!$this->body = file_get_contents($url))
7029 $this->error = 'file_get_contents could not read the file';
7030 $this->success = false;
7037 * Decode 'gzip' encoded HTTP data
7039 * @package SimplePie
7040 * @subpackage HTTP
7041 * @link http://www.gzip.org/format.txt
7043 class SimplePie_gzdecode
7046 * Compressed data
7048 * @access private
7049 * @var string
7050 * @see gzdecode::$data
7052 var $compressed_data;
7055 * Size of compressed data
7057 * @access private
7058 * @var int
7060 var $compressed_size;
7063 * Minimum size of a valid gzip string
7065 * @access private
7066 * @var int
7068 var $min_compressed_size = 18;
7071 * Current position of pointer
7073 * @access private
7074 * @var int
7076 var $position = 0;
7079 * Flags (FLG)
7081 * @access private
7082 * @var int
7084 var $flags;
7087 * Uncompressed data
7089 * @access public
7090 * @see gzdecode::$compressed_data
7091 * @var string
7093 var $data;
7096 * Modified time
7098 * @access public
7099 * @var int
7101 var $MTIME;
7104 * Extra Flags
7106 * @access public
7107 * @var int
7109 var $XFL;
7112 * Operating System
7114 * @access public
7115 * @var int
7117 var $OS;
7120 * Subfield ID 1
7122 * @access public
7123 * @see gzdecode::$extra_field
7124 * @see gzdecode::$SI2
7125 * @var string
7127 var $SI1;
7130 * Subfield ID 2
7132 * @access public
7133 * @see gzdecode::$extra_field
7134 * @see gzdecode::$SI1
7135 * @var string
7137 var $SI2;
7140 * Extra field content
7142 * @access public
7143 * @see gzdecode::$SI1
7144 * @see gzdecode::$SI2
7145 * @var string
7147 var $extra_field;
7150 * Original filename
7152 * @access public
7153 * @var string
7155 var $filename;
7158 * Human readable comment
7160 * @access public
7161 * @var string
7163 var $comment;
7166 * Don't allow anything to be set
7168 * @param string $name
7169 * @param mixed $value
7171 public function __set($name, $value)
7173 trigger_error("Cannot write property $name", E_USER_ERROR);
7177 * Set the compressed string and related properties
7179 * @param string $data
7181 public function __construct($data)
7183 $this->compressed_data = $data;
7184 $this->compressed_size = strlen($data);
7188 * Decode the GZIP stream
7190 * @return bool Successfulness
7192 public function parse()
7194 if ($this->compressed_size >= $this->min_compressed_size)
7196 // Check ID1, ID2, and CM
7197 if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
7199 return false;
7202 // Get the FLG (FLaGs)
7203 $this->flags = ord($this->compressed_data[3]);
7205 // FLG bits above (1 << 4) are reserved
7206 if ($this->flags > 0x1F)
7208 return false;
7211 // Advance the pointer after the above
7212 $this->position += 4;
7214 // MTIME
7215 $mtime = substr($this->compressed_data, $this->position, 4);
7216 // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
7217 if (current(unpack('S', "\x00\x01")) === 1)
7219 $mtime = strrev($mtime);
7221 $this->MTIME = current(unpack('l', $mtime));
7222 $this->position += 4;
7224 // Get the XFL (eXtra FLags)
7225 $this->XFL = ord($this->compressed_data[$this->position++]);
7227 // Get the OS (Operating System)
7228 $this->OS = ord($this->compressed_data[$this->position++]);
7230 // Parse the FEXTRA
7231 if ($this->flags & 4)
7233 // Read subfield IDs
7234 $this->SI1 = $this->compressed_data[$this->position++];
7235 $this->SI2 = $this->compressed_data[$this->position++];
7237 // SI2 set to zero is reserved for future use
7238 if ($this->SI2 === "\x00")
7240 return false;
7243 // Get the length of the extra field
7244 $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7245 $this->position += 2;
7247 // Check the length of the string is still valid
7248 $this->min_compressed_size += $len + 4;
7249 if ($this->compressed_size >= $this->min_compressed_size)
7251 // Set the extra field to the given data
7252 $this->extra_field = substr($this->compressed_data, $this->position, $len);
7253 $this->position += $len;
7255 else
7257 return false;
7261 // Parse the FNAME
7262 if ($this->flags & 8)
7264 // Get the length of the filename
7265 $len = strcspn($this->compressed_data, "\x00", $this->position);
7267 // Check the length of the string is still valid
7268 $this->min_compressed_size += $len + 1;
7269 if ($this->compressed_size >= $this->min_compressed_size)
7271 // Set the original filename to the given string
7272 $this->filename = substr($this->compressed_data, $this->position, $len);
7273 $this->position += $len + 1;
7275 else
7277 return false;
7281 // Parse the FCOMMENT
7282 if ($this->flags & 16)
7284 // Get the length of the comment
7285 $len = strcspn($this->compressed_data, "\x00", $this->position);
7287 // Check the length of the string is still valid
7288 $this->min_compressed_size += $len + 1;
7289 if ($this->compressed_size >= $this->min_compressed_size)
7291 // Set the original comment to the given string
7292 $this->comment = substr($this->compressed_data, $this->position, $len);
7293 $this->position += $len + 1;
7295 else
7297 return false;
7301 // Parse the FHCRC
7302 if ($this->flags & 2)
7304 // Check the length of the string is still valid
7305 $this->min_compressed_size += $len + 2;
7306 if ($this->compressed_size >= $this->min_compressed_size)
7308 // Read the CRC
7309 $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7311 // Check the CRC matches
7312 if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
7314 $this->position += 2;
7316 else
7318 return false;
7321 else
7323 return false;
7327 // Decompress the actual data
7328 if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
7330 return false;
7332 else
7334 $this->position = $this->compressed_size - 8;
7337 // Check CRC of data
7338 $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7339 $this->position += 4;
7340 /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
7342 return false;
7345 // Check ISIZE of data
7346 $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7347 $this->position += 4;
7348 if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
7350 return false;
7353 // Wow, against all odds, we've actually got a valid gzip string
7354 return true;
7356 else
7358 return false;
7364 * HTTP Response Parser
7366 * @package SimplePie
7367 * @subpackage HTTP
7369 class SimplePie_HTTP_Parser
7372 * HTTP Version
7374 * @var float
7376 public $http_version = 0.0;
7379 * Status code
7381 * @var int
7383 public $status_code = 0;
7386 * Reason phrase
7388 * @var string
7390 public $reason = '';
7393 * Key/value pairs of the headers
7395 * @var array
7397 public $headers = array();
7400 * Body of the response
7402 * @var string
7404 public $body = '';
7407 * Current state of the state machine
7409 * @var string
7411 protected $state = 'http_version';
7414 * Input data
7416 * @var string
7418 protected $data = '';
7421 * Input data length (to avoid calling strlen() everytime this is needed)
7423 * @var int
7425 protected $data_length = 0;
7428 * Current position of the pointer
7430 * @var int
7432 protected $position = 0;
7435 * Name of the hedaer currently being parsed
7437 * @var string
7439 protected $name = '';
7442 * Value of the hedaer currently being parsed
7444 * @var string
7446 protected $value = '';
7449 * Create an instance of the class with the input data
7451 * @param string $data Input data
7453 public function __construct($data)
7455 $this->data = $data;
7456 $this->data_length = strlen($this->data);
7460 * Parse the input data
7462 * @return bool true on success, false on failure
7464 public function parse()
7466 while ($this->state && $this->state !== 'emit' && $this->has_data())
7468 $state = $this->state;
7469 $this->$state();
7471 $this->data = '';
7472 if ($this->state === 'emit' || $this->state === 'body')
7474 return true;
7476 else
7478 $this->http_version = '';
7479 $this->status_code = '';
7480 $this->reason = '';
7481 $this->headers = array();
7482 $this->body = '';
7483 return false;
7488 * Check whether there is data beyond the pointer
7490 * @return bool true if there is further data, false if not
7492 protected function has_data()
7494 return (bool) ($this->position < $this->data_length);
7498 * See if the next character is LWS
7500 * @return bool true if the next character is LWS, false if not
7502 protected function is_linear_whitespace()
7504 return (bool) ($this->data[$this->position] === "\x09"
7505 || $this->data[$this->position] === "\x20"
7506 || ($this->data[$this->position] === "\x0A"
7507 && isset($this->data[$this->position + 1])
7508 && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
7512 * Parse the HTTP version
7514 protected function http_version()
7516 if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
7518 $len = strspn($this->data, '0123456789.', 5);
7519 $this->http_version = substr($this->data, 5, $len);
7520 $this->position += 5 + $len;
7521 if (substr_count($this->http_version, '.') <= 1)
7523 $this->http_version = (float) $this->http_version;
7524 $this->position += strspn($this->data, "\x09\x20", $this->position);
7525 $this->state = 'status';
7527 else
7529 $this->state = false;
7532 else
7534 $this->state = false;
7539 * Parse the status code
7541 protected function status()
7543 if ($len = strspn($this->data, '0123456789', $this->position))
7545 $this->status_code = (int) substr($this->data, $this->position, $len);
7546 $this->position += $len;
7547 $this->state = 'reason';
7549 else
7551 $this->state = false;
7556 * Parse the reason phrase
7558 protected function reason()
7560 $len = strcspn($this->data, "\x0A", $this->position);
7561 $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
7562 $this->position += $len + 1;
7563 $this->state = 'new_line';
7567 * Deal with a new line, shifting data around as needed
7569 protected function new_line()
7571 $this->value = trim($this->value, "\x0D\x20");
7572 if ($this->name !== '' && $this->value !== '')
7574 $this->name = strtolower($this->name);
7575 // We should only use the last Content-Type header. c.f. issue #1
7576 if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
7578 $this->headers[$this->name] .= ', ' . $this->value;
7580 else
7582 $this->headers[$this->name] = $this->value;
7585 $this->name = '';
7586 $this->value = '';
7587 if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
7589 $this->position += 2;
7590 $this->state = 'body';
7592 elseif ($this->data[$this->position] === "\x0A")
7594 $this->position++;
7595 $this->state = 'body';
7597 else
7599 $this->state = 'name';
7604 * Parse a header name
7606 protected function name()
7608 $len = strcspn($this->data, "\x0A:", $this->position);
7609 if (isset($this->data[$this->position + $len]))
7611 if ($this->data[$this->position + $len] === "\x0A")
7613 $this->position += $len;
7614 $this->state = 'new_line';
7616 else
7618 $this->name = substr($this->data, $this->position, $len);
7619 $this->position += $len + 1;
7620 $this->state = 'value';
7623 else
7625 $this->state = false;
7630 * Parse LWS, replacing consecutive LWS characters with a single space
7632 protected function linear_whitespace()
7636 if (substr($this->data, $this->position, 2) === "\x0D\x0A")
7638 $this->position += 2;
7640 elseif ($this->data[$this->position] === "\x0A")
7642 $this->position++;
7644 $this->position += strspn($this->data, "\x09\x20", $this->position);
7645 } while ($this->has_data() && $this->is_linear_whitespace());
7646 $this->value .= "\x20";
7650 * See what state to move to while within non-quoted header values
7652 protected function value()
7654 if ($this->is_linear_whitespace())
7656 $this->linear_whitespace();
7658 else
7660 switch ($this->data[$this->position])
7662 case '"':
7663 // Workaround for ETags: we have to include the quotes as
7664 // part of the tag.
7665 if (strtolower($this->name) === 'etag')
7667 $this->value .= '"';
7668 $this->position++;
7669 $this->state = 'value_char';
7670 break;
7672 $this->position++;
7673 $this->state = 'quote';
7674 break;
7676 case "\x0A":
7677 $this->position++;
7678 $this->state = 'new_line';
7679 break;
7681 default:
7682 $this->state = 'value_char';
7683 break;
7689 * Parse a header value while outside quotes
7691 protected function value_char()
7693 $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
7694 $this->value .= substr($this->data, $this->position, $len);
7695 $this->position += $len;
7696 $this->state = 'value';
7700 * See what state to move to while within quoted header values
7702 protected function quote()
7704 if ($this->is_linear_whitespace())
7706 $this->linear_whitespace();
7708 else
7710 switch ($this->data[$this->position])
7712 case '"':
7713 $this->position++;
7714 $this->state = 'value';
7715 break;
7717 case "\x0A":
7718 $this->position++;
7719 $this->state = 'new_line';
7720 break;
7722 case '\\':
7723 $this->position++;
7724 $this->state = 'quote_escaped';
7725 break;
7727 default:
7728 $this->state = 'quote_char';
7729 break;
7735 * Parse a header value while within quotes
7737 protected function quote_char()
7739 $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
7740 $this->value .= substr($this->data, $this->position, $len);
7741 $this->position += $len;
7742 $this->state = 'value';
7746 * Parse an escaped character within quotes
7748 protected function quote_escaped()
7750 $this->value .= $this->data[$this->position];
7751 $this->position++;
7752 $this->state = 'quote';
7756 * Parse the body
7758 protected function body()
7760 $this->body = substr($this->data, $this->position);
7761 if (!empty($this->headers['transfer-encoding']))
7763 unset($this->headers['transfer-encoding']);
7764 $this->state = 'chunked';
7766 else
7768 $this->state = 'emit';
7773 * Parsed a "Transfer-Encoding: chunked" body
7775 protected function chunked()
7777 if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
7779 $this->state = 'emit';
7780 return;
7783 $decoded = '';
7784 $encoded = $this->body;
7786 while (true)
7788 $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
7789 if (!$is_chunked)
7791 // Looks like it's not chunked after all
7792 $this->state = 'emit';
7793 return;
7796 $length = hexdec(trim($matches[1]));
7797 if ($length === 0)
7799 // Ignore trailer headers
7800 $this->state = 'emit';
7801 $this->body = $decoded;
7802 return;
7805 $chunk_length = strlen($matches[0]);
7806 $decoded .= $part = substr($encoded, $chunk_length, $length);
7807 $encoded = substr($encoded, $chunk_length + $length + 2);
7809 if (trim($encoded) === '0' || empty($encoded))
7811 $this->state = 'emit';
7812 $this->body = $decoded;
7813 return;
7820 * IRI parser/serialiser/normaliser
7822 * @package SimplePie
7823 * @subpackage HTTP
7824 * @author Geoffrey Sneddon
7825 * @author Steve Minutillo
7826 * @author Ryan McCue
7827 * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
7828 * @license http://www.opensource.org/licenses/bsd-license.php
7830 class SimplePie_IRI
7833 * Scheme
7835 * @var string
7837 protected $scheme = null;
7840 * User Information
7842 * @var string
7844 protected $iuserinfo = null;
7847 * ihost
7849 * @var string
7851 protected $ihost = null;
7854 * Port
7856 * @var string
7858 protected $port = null;
7861 * ipath
7863 * @var string
7865 protected $ipath = '';
7868 * iquery
7870 * @var string
7872 protected $iquery = null;
7875 * ifragment
7877 * @var string
7879 protected $ifragment = null;
7882 * Normalization database
7884 * Each key is the scheme, each value is an array with each key as the IRI
7885 * part and value as the default value for that part.
7887 protected $normalization = array(
7888 'acap' => array(
7889 'port' => 674
7891 'dict' => array(
7892 'port' => 2628
7894 'file' => array(
7895 'ihost' => 'localhost'
7897 'http' => array(
7898 'port' => 80,
7899 'ipath' => '/'
7901 'https' => array(
7902 'port' => 443,
7903 'ipath' => '/'
7908 * Return the entire IRI when you try and read the object as a string
7910 * @return string
7912 public function __toString()
7914 return $this->get_iri();
7918 * Overload __set() to provide access via properties
7920 * @param string $name Property name
7921 * @param mixed $value Property value
7923 public function __set($name, $value)
7925 if (method_exists($this, 'set_' . $name))
7927 call_user_func(array($this, 'set_' . $name), $value);
7929 elseif (
7930 $name === 'iauthority'
7931 || $name === 'iuserinfo'
7932 || $name === 'ihost'
7933 || $name === 'ipath'
7934 || $name === 'iquery'
7935 || $name === 'ifragment'
7938 call_user_func(array($this, 'set_' . substr($name, 1)), $value);
7943 * Overload __get() to provide access via properties
7945 * @param string $name Property name
7946 * @return mixed
7948 public function __get($name)
7950 // isset() returns false for null, we don't want to do that
7951 // Also why we use array_key_exists below instead of isset()
7952 $props = get_object_vars($this);
7954 if (
7955 $name === 'iri' ||
7956 $name === 'uri' ||
7957 $name === 'iauthority' ||
7958 $name === 'authority'
7961 $return = $this->{"get_$name"}();
7963 elseif (array_key_exists($name, $props))
7965 $return = $this->$name;
7967 // host -> ihost
7968 elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
7970 $name = $prop;
7971 $return = $this->$prop;
7973 // ischeme -> scheme
7974 elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
7976 $name = $prop;
7977 $return = $this->$prop;
7979 else
7981 trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
7982 $return = null;
7985 if ($return === null && isset($this->normalization[$this->scheme][$name]))
7987 return $this->normalization[$this->scheme][$name];
7989 else
7991 return $return;
7996 * Overload __isset() to provide access via properties
7998 * @param string $name Property name
7999 * @return bool
8001 public function __isset($name)
8003 if (method_exists($this, 'get_' . $name) || isset($this->$name))
8005 return true;
8007 else
8009 return false;
8014 * Overload __unset() to provide access via properties
8016 * @param string $name Property name
8018 public function __unset($name)
8020 if (method_exists($this, 'set_' . $name))
8022 call_user_func(array($this, 'set_' . $name), '');
8027 * Create a new IRI object, from a specified string
8029 * @param string $iri
8031 public function __construct($iri = null)
8033 $this->set_iri($iri);
8037 * Create a new IRI object by resolving a relative IRI
8039 * Returns false if $base is not absolute, otherwise an IRI.
8041 * @param IRI|string $base (Absolute) Base IRI
8042 * @param IRI|string $relative Relative IRI
8043 * @return IRI|false
8045 public static function absolutize($base, $relative)
8047 if (!($relative instanceof SimplePie_IRI))
8049 $relative = new SimplePie_IRI($relative);
8051 if (!$relative->is_valid())
8053 return false;
8055 elseif ($relative->scheme !== null)
8057 return clone $relative;
8059 else
8061 if (!($base instanceof SimplePie_IRI))
8063 $base = new SimplePie_IRI($base);
8065 if ($base->scheme !== null && $base->is_valid())
8067 if ($relative->get_iri() !== '')
8069 if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
8071 $target = clone $relative;
8072 $target->scheme = $base->scheme;
8074 else
8076 $target = new SimplePie_IRI;
8077 $target->scheme = $base->scheme;
8078 $target->iuserinfo = $base->iuserinfo;
8079 $target->ihost = $base->ihost;
8080 $target->port = $base->port;
8081 if ($relative->ipath !== '')
8083 if ($relative->ipath[0] === '/')
8085 $target->ipath = $relative->ipath;
8087 elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
8089 $target->ipath = '/' . $relative->ipath;
8091 elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
8093 $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
8095 else
8097 $target->ipath = $relative->ipath;
8099 $target->ipath = $target->remove_dot_segments($target->ipath);
8100 $target->iquery = $relative->iquery;
8102 else
8104 $target->ipath = $base->ipath;
8105 if ($relative->iquery !== null)
8107 $target->iquery = $relative->iquery;
8109 elseif ($base->iquery !== null)
8111 $target->iquery = $base->iquery;
8114 $target->ifragment = $relative->ifragment;
8117 else
8119 $target = clone $base;
8120 $target->ifragment = null;
8122 $target->scheme_normalization();
8123 return $target;
8125 else
8127 return false;
8133 * Parse an IRI into scheme/authority/path/query/fragment segments
8135 * @param string $iri
8136 * @return array
8138 protected function parse_iri($iri)
8140 $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
8141 if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
8143 if ($match[1] === '')
8145 $match['scheme'] = null;
8147 if (!isset($match[3]) || $match[3] === '')
8149 $match['authority'] = null;
8151 if (!isset($match[5]))
8153 $match['path'] = '';
8155 if (!isset($match[6]) || $match[6] === '')
8157 $match['query'] = null;
8159 if (!isset($match[8]) || $match[8] === '')
8161 $match['fragment'] = null;
8163 return $match;
8165 else
8167 // This can occur when a paragraph is accidentally parsed as a URI
8168 return false;
8173 * Remove dot segments from a path
8175 * @param string $input
8176 * @return string
8178 protected function remove_dot_segments($input)
8180 $output = '';
8181 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
8183 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
8184 if (strpos($input, '../') === 0)
8186 $input = substr($input, 3);
8188 elseif (strpos($input, './') === 0)
8190 $input = substr($input, 2);
8192 // 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,
8193 elseif (strpos($input, '/./') === 0)
8195 $input = substr($input, 2);
8197 elseif ($input === '/.')
8199 $input = '/';
8201 // 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,
8202 elseif (strpos($input, '/../') === 0)
8204 $input = substr($input, 3);
8205 $output = substr_replace($output, '', strrpos($output, '/'));
8207 elseif ($input === '/..')
8209 $input = '/';
8210 $output = substr_replace($output, '', strrpos($output, '/'));
8212 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
8213 elseif ($input === '.' || $input === '..')
8215 $input = '';
8217 // 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
8218 elseif (($pos = strpos($input, '/', 1)) !== false)
8220 $output .= substr($input, 0, $pos);
8221 $input = substr_replace($input, '', 0, $pos);
8223 else
8225 $output .= $input;
8226 $input = '';
8229 return $output . $input;
8233 * Replace invalid character with percent encoding
8235 * @param string $string Input string
8236 * @param string $extra_chars Valid characters not in iunreserved or
8237 * iprivate (this is ASCII-only)
8238 * @param bool $iprivate Allow iprivate
8239 * @return string
8241 protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
8243 // Normalize as many pct-encoded sections as possible
8244 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
8246 // Replace invalid percent characters
8247 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
8249 // Add unreserved and % to $extra_chars (the latter is safe because all
8250 // pct-encoded sections are now valid).
8251 $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
8253 // Now replace any bytes that aren't allowed with their pct-encoded versions
8254 $position = 0;
8255 $strlen = strlen($string);
8256 while (($position += strspn($string, $extra_chars, $position)) < $strlen)
8258 $value = ord($string[$position]);
8260 // Start position
8261 $start = $position;
8263 // By default we are valid
8264 $valid = true;
8266 // No one byte sequences are valid due to the while.
8267 // Two byte sequence:
8268 if (($value & 0xE0) === 0xC0)
8270 $character = ($value & 0x1F) << 6;
8271 $length = 2;
8272 $remaining = 1;
8274 // Three byte sequence:
8275 elseif (($value & 0xF0) === 0xE0)
8277 $character = ($value & 0x0F) << 12;
8278 $length = 3;
8279 $remaining = 2;
8281 // Four byte sequence:
8282 elseif (($value & 0xF8) === 0xF0)
8284 $character = ($value & 0x07) << 18;
8285 $length = 4;
8286 $remaining = 3;
8288 // Invalid byte:
8289 else
8291 $valid = false;
8292 $length = 1;
8293 $remaining = 0;
8296 if ($remaining)
8298 if ($position + $length <= $strlen)
8300 for ($position++; $remaining; $position++)
8302 $value = ord($string[$position]);
8304 // Check that the byte is valid, then add it to the character:
8305 if (($value & 0xC0) === 0x80)
8307 $character |= ($value & 0x3F) << (--$remaining * 6);
8309 // If it is invalid, count the sequence as invalid and reprocess the current byte:
8310 else
8312 $valid = false;
8313 $position--;
8314 break;
8318 else
8320 $position = $strlen - 1;
8321 $valid = false;
8325 // Percent encode anything invalid or not in ucschar
8326 if (
8327 // Invalid sequences
8328 !$valid
8329 // Non-shortest form sequences are invalid
8330 || $length > 1 && $character <= 0x7F
8331 || $length > 2 && $character <= 0x7FF
8332 || $length > 3 && $character <= 0xFFFF
8333 // Outside of range of ucschar codepoints
8334 // Noncharacters
8335 || ($character & 0xFFFE) === 0xFFFE
8336 || $character >= 0xFDD0 && $character <= 0xFDEF
8337 || (
8338 // Everything else not in ucschar
8339 $character > 0xD7FF && $character < 0xF900
8340 || $character < 0xA0
8341 || $character > 0xEFFFD
8343 && (
8344 // Everything not in iprivate, if it applies
8345 !$iprivate
8346 || $character < 0xE000
8347 || $character > 0x10FFFD
8351 // If we were a character, pretend we weren't, but rather an error.
8352 if ($valid)
8353 $position--;
8355 for ($j = $start; $j <= $position; $j++)
8357 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
8358 $j += 2;
8359 $position += 2;
8360 $strlen += 2;
8365 return $string;
8369 * Callback function for preg_replace_callback.
8371 * Removes sequences of percent encoded bytes that represent UTF-8
8372 * encoded characters in iunreserved
8374 * @param array $match PCRE match
8375 * @return string Replacement
8377 protected function remove_iunreserved_percent_encoded($match)
8379 // As we just have valid percent encoded sequences we can just explode
8380 // and ignore the first member of the returned array (an empty string).
8381 $bytes = explode('%', $match[0]);
8383 // Initialize the new string (this is what will be returned) and that
8384 // there are no bytes remaining in the current sequence (unsurprising
8385 // at the first byte!).
8386 $string = '';
8387 $remaining = 0;
8389 // Loop over each and every byte, and set $value to its value
8390 for ($i = 1, $len = count($bytes); $i < $len; $i++)
8392 $value = hexdec($bytes[$i]);
8394 // If we're the first byte of sequence:
8395 if (!$remaining)
8397 // Start position
8398 $start = $i;
8400 // By default we are valid
8401 $valid = true;
8403 // One byte sequence:
8404 if ($value <= 0x7F)
8406 $character = $value;
8407 $length = 1;
8409 // Two byte sequence:
8410 elseif (($value & 0xE0) === 0xC0)
8412 $character = ($value & 0x1F) << 6;
8413 $length = 2;
8414 $remaining = 1;
8416 // Three byte sequence:
8417 elseif (($value & 0xF0) === 0xE0)
8419 $character = ($value & 0x0F) << 12;
8420 $length = 3;
8421 $remaining = 2;
8423 // Four byte sequence:
8424 elseif (($value & 0xF8) === 0xF0)
8426 $character = ($value & 0x07) << 18;
8427 $length = 4;
8428 $remaining = 3;
8430 // Invalid byte:
8431 else
8433 $valid = false;
8434 $remaining = 0;
8437 // Continuation byte:
8438 else
8440 // Check that the byte is valid, then add it to the character:
8441 if (($value & 0xC0) === 0x80)
8443 $remaining--;
8444 $character |= ($value & 0x3F) << ($remaining * 6);
8446 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
8447 else
8449 $valid = false;
8450 $remaining = 0;
8451 $i--;
8455 // If we've reached the end of the current byte sequence, append it to Unicode::$data
8456 if (!$remaining)
8458 // Percent encode anything invalid or not in iunreserved
8459 if (
8460 // Invalid sequences
8461 !$valid
8462 // Non-shortest form sequences are invalid
8463 || $length > 1 && $character <= 0x7F
8464 || $length > 2 && $character <= 0x7FF
8465 || $length > 3 && $character <= 0xFFFF
8466 // Outside of range of iunreserved codepoints
8467 || $character < 0x2D
8468 || $character > 0xEFFFD
8469 // Noncharacters
8470 || ($character & 0xFFFE) === 0xFFFE
8471 || $character >= 0xFDD0 && $character <= 0xFDEF
8472 // Everything else not in iunreserved (this is all BMP)
8473 || $character === 0x2F
8474 || $character > 0x39 && $character < 0x41
8475 || $character > 0x5A && $character < 0x61
8476 || $character > 0x7A && $character < 0x7E
8477 || $character > 0x7E && $character < 0xA0
8478 || $character > 0xD7FF && $character < 0xF900
8481 for ($j = $start; $j <= $i; $j++)
8483 $string .= '%' . strtoupper($bytes[$j]);
8486 else
8488 for ($j = $start; $j <= $i; $j++)
8490 $string .= chr(hexdec($bytes[$j]));
8496 // If we have any bytes left over they are invalid (i.e., we are
8497 // mid-way through a multi-byte sequence)
8498 if ($remaining)
8500 for ($j = $start; $j < $len; $j++)
8502 $string .= '%' . strtoupper($bytes[$j]);
8506 return $string;
8509 protected function scheme_normalization()
8511 if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
8513 $this->iuserinfo = null;
8515 if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
8517 $this->ihost = null;
8519 if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
8521 $this->port = null;
8523 if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
8525 $this->ipath = '';
8527 if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
8529 $this->iquery = null;
8531 if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
8533 $this->ifragment = null;
8538 * Check if the object represents a valid IRI. This needs to be done on each
8539 * call as some things change depending on another part of the IRI.
8541 * @return bool
8543 public function is_valid()
8545 $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
8546 if ($this->ipath !== '' &&
8548 $isauthority && (
8549 $this->ipath[0] !== '/' ||
8550 substr($this->ipath, 0, 2) === '//'
8551 ) ||
8553 $this->scheme === null &&
8554 !$isauthority &&
8555 strpos($this->ipath, ':') !== false &&
8556 (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
8561 return false;
8564 return true;
8568 * Set the entire IRI. Returns true on success, false on failure (if there
8569 * are any invalid characters).
8571 * @param string $iri
8572 * @return bool
8574 public function set_iri($iri)
8576 static $cache;
8577 if (!$cache)
8579 $cache = array();
8582 if ($iri === null)
8584 return true;
8586 elseif (isset($cache[$iri]))
8588 list($this->scheme,
8589 $this->iuserinfo,
8590 $this->ihost,
8591 $this->port,
8592 $this->ipath,
8593 $this->iquery,
8594 $this->ifragment,
8595 $return) = $cache[$iri];
8596 return $return;
8598 else
8600 $parsed = $this->parse_iri((string) $iri);
8601 if (!$parsed)
8603 return false;
8606 $return = $this->set_scheme($parsed['scheme'])
8607 && $this->set_authority($parsed['authority'])
8608 && $this->set_path($parsed['path'])
8609 && $this->set_query($parsed['query'])
8610 && $this->set_fragment($parsed['fragment']);
8612 $cache[$iri] = array($this->scheme,
8613 $this->iuserinfo,
8614 $this->ihost,
8615 $this->port,
8616 $this->ipath,
8617 $this->iquery,
8618 $this->ifragment,
8619 $return);
8620 return $return;
8625 * Set the scheme. Returns true on success, false on failure (if there are
8626 * any invalid characters).
8628 * @param string $scheme
8629 * @return bool
8631 public function set_scheme($scheme)
8633 if ($scheme === null)
8635 $this->scheme = null;
8637 elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
8639 $this->scheme = null;
8640 return false;
8642 else
8644 $this->scheme = strtolower($scheme);
8646 return true;
8650 * Set the authority. Returns true on success, false on failure (if there are
8651 * any invalid characters).
8653 * @param string $authority
8654 * @return bool
8656 public function set_authority($authority)
8658 static $cache;
8659 if (!$cache)
8660 $cache = array();
8662 if ($authority === null)
8664 $this->iuserinfo = null;
8665 $this->ihost = null;
8666 $this->port = null;
8667 return true;
8669 elseif (isset($cache[$authority]))
8671 list($this->iuserinfo,
8672 $this->ihost,
8673 $this->port,
8674 $return) = $cache[$authority];
8676 return $return;
8678 else
8680 $remaining = $authority;
8681 if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
8683 $iuserinfo = substr($remaining, 0, $iuserinfo_end);
8684 $remaining = substr($remaining, $iuserinfo_end + 1);
8686 else
8688 $iuserinfo = null;
8690 if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
8692 if (($port = substr($remaining, $port_start + 1)) === false)
8694 $port = null;
8696 $remaining = substr($remaining, 0, $port_start);
8698 else
8700 $port = null;
8703 $return = $this->set_userinfo($iuserinfo) &&
8704 $this->set_host($remaining) &&
8705 $this->set_port($port);
8707 $cache[$authority] = array($this->iuserinfo,
8708 $this->ihost,
8709 $this->port,
8710 $return);
8712 return $return;
8717 * Set the iuserinfo.
8719 * @param string $iuserinfo
8720 * @return bool
8722 public function set_userinfo($iuserinfo)
8724 if ($iuserinfo === null)
8726 $this->iuserinfo = null;
8728 else
8730 $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
8731 $this->scheme_normalization();
8734 return true;
8738 * Set the ihost. Returns true on success, false on failure (if there are
8739 * any invalid characters).
8741 * @param string $ihost
8742 * @return bool
8744 public function set_host($ihost)
8746 if ($ihost === null)
8748 $this->ihost = null;
8749 return true;
8751 elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
8753 if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
8755 $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
8757 else
8759 $this->ihost = null;
8760 return false;
8763 else
8765 $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
8767 // Lowercase, but ignore pct-encoded sections (as they should
8768 // remain uppercase). This must be done after the previous step
8769 // as that can add unescaped characters.
8770 $position = 0;
8771 $strlen = strlen($ihost);
8772 while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
8774 if ($ihost[$position] === '%')
8776 $position += 3;
8778 else
8780 $ihost[$position] = strtolower($ihost[$position]);
8781 $position++;
8785 $this->ihost = $ihost;
8788 $this->scheme_normalization();
8790 return true;
8794 * Set the port. Returns true on success, false on failure (if there are
8795 * any invalid characters).
8797 * @param string $port
8798 * @return bool
8800 public function set_port($port)
8802 if ($port === null)
8804 $this->port = null;
8805 return true;
8807 elseif (strspn($port, '0123456789') === strlen($port))
8809 $this->port = (int) $port;
8810 $this->scheme_normalization();
8811 return true;
8813 else
8815 $this->port = null;
8816 return false;
8821 * Set the ipath.
8823 * @param string $ipath
8824 * @return bool
8826 public function set_path($ipath)
8828 static $cache;
8829 if (!$cache)
8831 $cache = array();
8834 $ipath = (string) $ipath;
8836 if (isset($cache[$ipath]))
8838 $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
8840 else
8842 $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
8843 $removed = $this->remove_dot_segments($valid);
8845 $cache[$ipath] = array($valid, $removed);
8846 $this->ipath = ($this->scheme !== null) ? $removed : $valid;
8849 $this->scheme_normalization();
8850 return true;
8854 * Set the iquery.
8856 * @param string $iquery
8857 * @return bool
8859 public function set_query($iquery)
8861 if ($iquery === null)
8863 $this->iquery = null;
8865 else
8867 $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
8868 $this->scheme_normalization();
8870 return true;
8874 * Set the ifragment.
8876 * @param string $ifragment
8877 * @return bool
8879 public function set_fragment($ifragment)
8881 if ($ifragment === null)
8883 $this->ifragment = null;
8885 else
8887 $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
8888 $this->scheme_normalization();
8890 return true;
8894 * Convert an IRI to a URI (or parts thereof)
8896 * @return string
8898 public function to_uri($string)
8900 static $non_ascii;
8901 if (!$non_ascii)
8903 $non_ascii = implode('', range("\x80", "\xFF"));
8906 $position = 0;
8907 $strlen = strlen($string);
8908 while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
8910 $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
8911 $position += 3;
8912 $strlen += 2;
8915 return $string;
8919 * Get the complete IRI
8921 * @return string
8923 public function get_iri()
8925 if (!$this->is_valid())
8927 return false;
8930 $iri = '';
8931 if ($this->scheme !== null)
8933 $iri .= $this->scheme . ':';
8935 if (($iauthority = $this->get_iauthority()) !== null)
8937 $iri .= '//' . $iauthority;
8939 if ($this->ipath !== '')
8941 $iri .= $this->ipath;
8943 elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
8945 $iri .= $this->normalization[$this->scheme]['ipath'];
8947 if ($this->iquery !== null)
8949 $iri .= '?' . $this->iquery;
8951 if ($this->ifragment !== null)
8953 $iri .= '#' . $this->ifragment;
8956 return $iri;
8960 * Get the complete URI
8962 * @return string
8964 public function get_uri()
8966 return $this->to_uri($this->get_iri());
8970 * Get the complete iauthority
8972 * @return string
8974 protected function get_iauthority()
8976 if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
8978 $iauthority = '';
8979 if ($this->iuserinfo !== null)
8981 $iauthority .= $this->iuserinfo . '@';
8983 if ($this->ihost !== null)
8985 $iauthority .= $this->ihost;
8987 if ($this->port !== null)
8989 $iauthority .= ':' . $this->port;
8991 return $iauthority;
8993 else
8995 return null;
9000 * Get the complete authority
9002 * @return string
9004 protected function get_authority()
9006 $iauthority = $this->get_iauthority();
9007 if (is_string($iauthority))
9008 return $this->to_uri($iauthority);
9009 else
9010 return $iauthority;
9015 * Manages all item-related data
9017 * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
9019 * This class can be overloaded with {@see SimplePie::set_item_class()}
9021 * @package SimplePie
9022 * @subpackage API
9024 class SimplePie_Item
9027 * Parent feed
9029 * @access private
9030 * @var SimplePie
9032 var $feed;
9035 * Raw data
9037 * @access private
9038 * @var array
9040 var $data = array();
9043 * Registry object
9045 * @see set_registry
9046 * @var SimplePie_Registry
9048 protected $registry;
9051 * Create a new item object
9053 * This is usually used by {@see SimplePie::get_items} and
9054 * {@see SimplePie::get_item}. Avoid creating this manually.
9056 * @param SimplePie $feed Parent feed
9057 * @param array $data Raw data
9059 public function __construct($feed, $data)
9061 $this->feed = $feed;
9062 $this->data = $data;
9066 * Set the registry handler
9068 * This is usually used by {@see SimplePie_Registry::create}
9070 * @since 1.3
9071 * @param SimplePie_Registry $registry
9073 public function set_registry(SimplePie_Registry $registry)
9075 $this->registry = $registry;
9079 * Get a string representation of the item
9081 * @return string
9083 public function __toString()
9085 return md5(serialize($this->data));
9089 * Remove items that link back to this before destroying this object
9091 public function __destruct()
9093 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
9095 unset($this->feed);
9100 * Get data for an item-level element
9102 * This method allows you to get access to ANY element/attribute that is a
9103 * sub-element of the item/entry tag.
9105 * See {@see SimplePie::get_feed_tags()} for a description of the return value
9107 * @since 1.0
9108 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
9109 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
9110 * @param string $tag Tag name
9111 * @return array
9113 public function get_item_tags($namespace, $tag)
9115 if (isset($this->data['child'][$namespace][$tag]))
9117 return $this->data['child'][$namespace][$tag];
9119 else
9121 return null;
9126 * Get the base URL value from the parent feed
9128 * Uses `<xml:base>`
9130 * @param array $element
9131 * @return string
9133 public function get_base($element = array())
9135 return $this->feed->get_base($element);
9139 * Sanitize feed data
9141 * @access private
9142 * @see SimplePie::sanitize()
9143 * @param string $data Data to sanitize
9144 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
9145 * @param string $base Base URL to resolve URLs against
9146 * @return string Sanitized data
9148 public function sanitize($data, $type, $base = '')
9150 return $this->feed->sanitize($data, $type, $base);
9154 * Get the parent feed
9156 * Note: this may not work as you think for multifeeds!
9158 * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
9159 * @since 1.0
9160 * @return SimplePie
9162 public function get_feed()
9164 return $this->feed;
9168 * Get the unique identifier for the item
9170 * This is usually used when writing code to check for new items in a feed.
9172 * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
9173 * for RDF. If none of these are supplied (or `$hash` is true), creates an
9174 * MD5 hash based on the permalink and title. If either of those are not
9175 * supplied, creates a hash based on the full feed data.
9177 * @since Beta 2
9178 * @param boolean $hash Should we force using a hash instead of the supplied ID?
9179 * @return string
9181 public function get_id($hash = false)
9183 if (!$hash)
9185 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
9187 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9189 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
9191 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9193 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9195 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9197 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
9199 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9201 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
9203 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9205 elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
9207 return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
9209 elseif (($return = $this->get_permalink()) !== null)
9211 return $return;
9213 elseif (($return = $this->get_title()) !== null)
9215 return $return;
9218 if ($this->get_permalink() !== null || $this->get_title() !== null)
9220 return md5($this->get_permalink() . $this->get_title());
9222 else
9224 return md5(serialize($this->data));
9229 * Get the title of the item
9231 * Uses `<atom:title>`, `<title>` or `<dc:title>`
9233 * @since Beta 2 (previously called `get_item_title` since 0.8)
9234 * @return string|null
9236 public function get_title()
9238 if (!isset($this->data['title']))
9240 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
9242 $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]));
9244 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
9246 $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]));
9248 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
9250 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9252 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
9254 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9256 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
9258 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9260 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
9262 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9264 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
9266 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9268 else
9270 $this->data['title'] = null;
9273 return $this->data['title'];
9277 * Get the content for the item
9279 * Prefers summaries over full content , but will return full content if a
9280 * summary does not exist.
9282 * To prefer full content instead, use {@see get_content}
9284 * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
9285 * `<itunes:subtitle>`
9287 * @since 0.8
9288 * @param boolean $description_only Should we avoid falling back to the content?
9289 * @return string|null
9291 public function get_description($description_only = false)
9293 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
9295 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9297 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
9299 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9301 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
9303 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9305 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
9307 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9309 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
9311 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9313 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
9315 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9317 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
9319 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9321 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
9323 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9325 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
9327 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
9330 elseif (!$description_only)
9332 return $this->get_content(true);
9334 else
9336 return null;
9341 * Get the content for the item
9343 * Prefers full content over summaries, but will return a summary if full
9344 * content does not exist.
9346 * To prefer summaries instead, use {@see get_description}
9348 * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
9350 * @since 1.0
9351 * @param boolean $content_only Should we avoid falling back to the description?
9352 * @return string|null
9354 public function get_content($content_only = false)
9356 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
9358 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9360 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
9362 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9364 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
9366 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9368 elseif (!$content_only)
9370 return $this->get_description(true);
9372 else
9374 return null;
9379 * Get a category for the item
9381 * @since Beta 3 (previously called `get_categories()` since Beta 2)
9382 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
9383 * @return SimplePie_Category|null
9385 public function get_category($key = 0)
9387 $categories = $this->get_categories();
9388 if (isset($categories[$key]))
9390 return $categories[$key];
9392 else
9394 return null;
9399 * Get all categories for the item
9401 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
9403 * @since Beta 3
9404 * @return array|null List of {@see SimplePie_Category} objects
9406 public function get_categories()
9408 $categories = array();
9410 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
9412 $term = null;
9413 $scheme = null;
9414 $label = null;
9415 if (isset($category['attribs']['']['term']))
9417 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
9419 if (isset($category['attribs']['']['scheme']))
9421 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
9423 if (isset($category['attribs']['']['label']))
9425 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
9427 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
9429 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
9431 // This is really the label, but keep this as the term also for BC.
9432 // Label will also work on retrieving because that falls back to term.
9433 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9434 if (isset($category['attribs']['']['domain']))
9436 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
9438 else
9440 $scheme = null;
9442 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
9444 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
9446 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9448 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
9450 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9453 if (!empty($categories))
9455 return array_unique($categories);
9457 else
9459 return null;
9464 * Get an author for the item
9466 * @since Beta 2
9467 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
9468 * @return SimplePie_Author|null
9470 public function get_author($key = 0)
9472 $authors = $this->get_authors();
9473 if (isset($authors[$key]))
9475 return $authors[$key];
9477 else
9479 return null;
9484 * Get a contributor for the item
9486 * @since 1.1
9487 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
9488 * @return SimplePie_Author|null
9490 public function get_contributor($key = 0)
9492 $contributors = $this->get_contributors();
9493 if (isset($contributors[$key]))
9495 return $contributors[$key];
9497 else
9499 return null;
9504 * Get all contributors for the item
9506 * Uses `<atom:contributor>`
9508 * @since 1.1
9509 * @return array|null List of {@see SimplePie_Author} objects
9511 public function get_contributors()
9513 $contributors = array();
9514 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
9516 $name = null;
9517 $uri = null;
9518 $email = null;
9519 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
9521 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9523 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
9525 $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]));
9527 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9529 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9531 if ($name !== null || $email !== null || $uri !== null)
9533 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
9536 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
9538 $name = null;
9539 $url = null;
9540 $email = null;
9541 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9543 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9545 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9547 $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]));
9549 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9551 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9553 if ($name !== null || $email !== null || $url !== null)
9555 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
9559 if (!empty($contributors))
9561 return array_unique($contributors);
9563 else
9565 return null;
9570 * Get all authors for the item
9572 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
9574 * @since Beta 2
9575 * @return array|null List of {@see SimplePie_Author} objects
9577 public function get_authors()
9579 $authors = array();
9580 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
9582 $name = null;
9583 $uri = null;
9584 $email = null;
9585 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
9587 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9589 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
9591 $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]));
9593 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9595 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9597 if ($name !== null || $email !== null || $uri !== null)
9599 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
9602 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
9604 $name = null;
9605 $url = null;
9606 $email = null;
9607 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9609 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9611 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9613 $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]));
9615 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9617 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9619 if ($name !== null || $email !== null || $url !== null)
9621 $authors[] = $this->registry->create('Author', array($name, $url, $email));
9624 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
9626 $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
9628 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
9630 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9632 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
9634 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9636 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
9638 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9641 if (!empty($authors))
9643 return array_unique($authors);
9645 elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
9647 return $authors;
9649 elseif ($authors = $this->feed->get_authors())
9651 return $authors;
9653 else
9655 return null;
9660 * Get the copyright info for the item
9662 * Uses `<atom:rights>` or `<dc:rights>`
9664 * @since 1.1
9665 * @return string
9667 public function get_copyright()
9669 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
9671 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9673 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
9675 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9677 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
9679 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9681 else
9683 return null;
9688 * Get the posting date/time for the item
9690 * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
9691 * `<atom:modified>`, `<pubDate>` or `<dc:date>`
9693 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9694 * {@see get_gmdate}
9696 * @since Beta 2 (previously called `get_item_date` since 0.8)
9698 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9699 * @return int|string|null
9701 public function get_date($date_format = 'j F Y, g:i a')
9703 if (!isset($this->data['date']))
9705 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
9707 $this->data['date']['raw'] = $return[0]['data'];
9709 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9711 $this->data['date']['raw'] = $return[0]['data'];
9713 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
9715 $this->data['date']['raw'] = $return[0]['data'];
9717 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
9719 $this->data['date']['raw'] = $return[0]['data'];
9721 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
9723 $this->data['date']['raw'] = $return[0]['data'];
9725 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
9727 $this->data['date']['raw'] = $return[0]['data'];
9729 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
9731 $this->data['date']['raw'] = $return[0]['data'];
9733 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
9735 $this->data['date']['raw'] = $return[0]['data'];
9738 if (!empty($this->data['date']['raw']))
9740 $parser = $this->registry->call('Parse_Date', 'get');
9741 $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
9743 else
9745 $this->data['date'] = null;
9748 if ($this->data['date'])
9750 $date_format = (string) $date_format;
9751 switch ($date_format)
9753 case '':
9754 return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
9756 case 'U':
9757 return $this->data['date']['parsed'];
9759 default:
9760 return date($date_format, $this->data['date']['parsed']);
9763 else
9765 return null;
9770 * Get the update date/time for the item
9772 * Uses `<atom:updated>`
9774 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9775 * {@see get_gmdate}
9777 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9778 * @return int|string|null
9780 public function get_updated_date($date_format = 'j F Y, g:i a')
9782 if (!isset($this->data['updated']))
9784 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9786 $this->data['updated']['raw'] = $return[0]['data'];
9789 if (!empty($this->data['updated']['raw']))
9791 $parser = $this->registry->call('Parse_Date', 'get');
9792 $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
9794 else
9796 $this->data['updated'] = null;
9799 if ($this->data['updated'])
9801 $date_format = (string) $date_format;
9802 switch ($date_format)
9804 case '':
9805 return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
9807 case 'U':
9808 return $this->data['updated']['parsed'];
9810 default:
9811 return date($date_format, $this->data['updated']['parsed']);
9814 else
9816 return null;
9821 * Get the localized posting date/time for the item
9823 * Returns the date formatted in the localized language. To display in
9824 * languages other than the server's default, you need to change the locale
9825 * with {@link http://php.net/setlocale setlocale()}. The available
9826 * localizations depend on which ones are installed on your web server.
9828 * @since 1.0
9830 * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
9831 * @return int|string|null
9833 public function get_local_date($date_format = '%c')
9835 if (!$date_format)
9837 return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
9839 elseif (($date = $this->get_date('U')) !== null && $date !== false)
9841 return strftime($date_format, $date);
9843 else
9845 return null;
9850 * Get the posting date/time for the item (UTC time)
9852 * @see get_date
9853 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9854 * @return int|string|null
9856 public function get_gmdate($date_format = 'j F Y, g:i a')
9858 $date = $this->get_date('U');
9859 if ($date === null)
9861 return null;
9864 return gmdate($date_format, $date);
9868 * Get the update date/time for the item (UTC time)
9870 * @see get_updated_date
9871 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9872 * @return int|string|null
9874 public function get_updated_gmdate($date_format = 'j F Y, g:i a')
9876 $date = $this->get_updated_date('U');
9877 if ($date === null)
9879 return null;
9882 return gmdate($date_format, $date);
9886 * Get the permalink for the item
9888 * Returns the first link available with a relationship of "alternate".
9889 * Identical to {@see get_link()} with key 0
9891 * @see get_link
9892 * @since 0.8
9893 * @return string|null Permalink URL
9895 public function get_permalink()
9897 $link = $this->get_link();
9898 $enclosure = $this->get_enclosure(0);
9899 if ($link !== null)
9901 return $link;
9903 elseif ($enclosure !== null)
9905 return $enclosure->get_link();
9907 else
9909 return null;
9914 * Get a single link for the item
9916 * @since Beta 3
9917 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
9918 * @param string $rel The relationship of the link to return
9919 * @return string|null Link URL
9921 public function get_link($key = 0, $rel = 'alternate')
9923 $links = $this->get_links($rel);
9924 if ($links[$key] !== null)
9926 return $links[$key];
9928 else
9930 return null;
9935 * Get all links for the item
9937 * Uses `<atom:link>`, `<link>` or `<guid>`
9939 * @since Beta 2
9940 * @param string $rel The relationship of links to return
9941 * @return array|null Links found for the item (strings)
9943 public function get_links($rel = 'alternate')
9945 if (!isset($this->data['links']))
9947 $this->data['links'] = array();
9948 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
9950 if (isset($link['attribs']['']['href']))
9952 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9953 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
9957 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
9959 if (isset($link['attribs']['']['href']))
9961 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9962 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
9965 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
9967 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9969 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
9971 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9973 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
9975 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9977 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9979 if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
9981 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9985 $keys = array_keys($this->data['links']);
9986 foreach ($keys as $key)
9988 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
9990 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
9992 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
9993 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
9995 else
9997 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
10000 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
10002 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
10004 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
10007 if (isset($this->data['links'][$rel]))
10009 return $this->data['links'][$rel];
10011 else
10013 return null;
10018 * Get an enclosure from the item
10020 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10022 * @since Beta 2
10023 * @todo Add ability to prefer one type of content over another (in a media group).
10024 * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
10025 * @return SimplePie_Enclosure|null
10027 public function get_enclosure($key = 0, $prefer = null)
10029 $enclosures = $this->get_enclosures();
10030 if (isset($enclosures[$key]))
10032 return $enclosures[$key];
10034 else
10036 return null;
10041 * Get all available enclosures (podcasts, etc.)
10043 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10045 * At this point, we're pretty much assuming that all enclosures for an item
10046 * are the same content. Anything else is too complicated to
10047 * properly support.
10049 * @since Beta 2
10050 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
10051 * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
10052 * @return array|null List of SimplePie_Enclosure items
10054 public function get_enclosures()
10056 if (!isset($this->data['enclosures']))
10058 $this->data['enclosures'] = array();
10060 // Elements
10061 $captions_parent = null;
10062 $categories_parent = null;
10063 $copyrights_parent = null;
10064 $credits_parent = null;
10065 $description_parent = null;
10066 $duration_parent = null;
10067 $hashes_parent = null;
10068 $keywords_parent = null;
10069 $player_parent = null;
10070 $ratings_parent = null;
10071 $restrictions_parent = null;
10072 $thumbnails_parent = null;
10073 $title_parent = null;
10075 // Let's do the channel and item-level ones first, and just re-use them if we need to.
10076 $parent = $this->get_feed();
10078 // CAPTIONS
10079 if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10081 foreach ($captions as $caption)
10083 $caption_type = null;
10084 $caption_lang = null;
10085 $caption_startTime = null;
10086 $caption_endTime = null;
10087 $caption_text = null;
10088 if (isset($caption['attribs']['']['type']))
10090 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10092 if (isset($caption['attribs']['']['lang']))
10094 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10096 if (isset($caption['attribs']['']['start']))
10098 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10100 if (isset($caption['attribs']['']['end']))
10102 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10104 if (isset($caption['data']))
10106 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10108 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10111 elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10113 foreach ($captions as $caption)
10115 $caption_type = null;
10116 $caption_lang = null;
10117 $caption_startTime = null;
10118 $caption_endTime = null;
10119 $caption_text = null;
10120 if (isset($caption['attribs']['']['type']))
10122 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10124 if (isset($caption['attribs']['']['lang']))
10126 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10128 if (isset($caption['attribs']['']['start']))
10130 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10132 if (isset($caption['attribs']['']['end']))
10134 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10136 if (isset($caption['data']))
10138 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10140 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10143 if (is_array($captions_parent))
10145 $captions_parent = array_values(array_unique($captions_parent));
10148 // CATEGORIES
10149 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
10151 $term = null;
10152 $scheme = null;
10153 $label = null;
10154 if (isset($category['data']))
10156 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10158 if (isset($category['attribs']['']['scheme']))
10160 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10162 else
10164 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10166 if (isset($category['attribs']['']['label']))
10168 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10170 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10172 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
10174 $term = null;
10175 $scheme = null;
10176 $label = null;
10177 if (isset($category['data']))
10179 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10181 if (isset($category['attribs']['']['scheme']))
10183 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10185 else
10187 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10189 if (isset($category['attribs']['']['label']))
10191 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10193 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10195 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
10197 $term = null;
10198 $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
10199 $label = null;
10200 if (isset($category['attribs']['']['text']))
10202 $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10204 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10206 if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
10208 foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
10210 if (isset($subcategory['attribs']['']['text']))
10212 $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10214 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10218 if (is_array($categories_parent))
10220 $categories_parent = array_values(array_unique($categories_parent));
10223 // COPYRIGHT
10224 if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
10226 $copyright_url = null;
10227 $copyright_label = null;
10228 if (isset($copyright[0]['attribs']['']['url']))
10230 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10232 if (isset($copyright[0]['data']))
10234 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10236 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10238 elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
10240 $copyright_url = null;
10241 $copyright_label = null;
10242 if (isset($copyright[0]['attribs']['']['url']))
10244 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10246 if (isset($copyright[0]['data']))
10248 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10250 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10253 // CREDITS
10254 if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
10256 foreach ($credits as $credit)
10258 $credit_role = null;
10259 $credit_scheme = null;
10260 $credit_name = null;
10261 if (isset($credit['attribs']['']['role']))
10263 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10265 if (isset($credit['attribs']['']['scheme']))
10267 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10269 else
10271 $credit_scheme = 'urn:ebu';
10273 if (isset($credit['data']))
10275 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10277 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
10280 elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
10282 foreach ($credits as $credit)
10284 $credit_role = null;
10285 $credit_scheme = null;
10286 $credit_name = null;
10287 if (isset($credit['attribs']['']['role']))
10289 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10291 if (isset($credit['attribs']['']['scheme']))
10293 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10295 else
10297 $credit_scheme = 'urn:ebu';
10299 if (isset($credit['data']))
10301 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10303 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
10306 if (is_array($credits_parent))
10308 $credits_parent = array_values(array_unique($credits_parent));
10311 // DESCRIPTION
10312 if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
10314 if (isset($description_parent[0]['data']))
10316 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10319 elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
10321 if (isset($description_parent[0]['data']))
10323 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10327 // DURATION
10328 if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
10330 $seconds = null;
10331 $minutes = null;
10332 $hours = null;
10333 if (isset($duration_parent[0]['data']))
10335 $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10336 if (sizeof($temp) > 0)
10338 $seconds = (int) array_pop($temp);
10340 if (sizeof($temp) > 0)
10342 $minutes = (int) array_pop($temp);
10343 $seconds += $minutes * 60;
10345 if (sizeof($temp) > 0)
10347 $hours = (int) array_pop($temp);
10348 $seconds += $hours * 3600;
10350 unset($temp);
10351 $duration_parent = $seconds;
10355 // HASHES
10356 if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
10358 foreach ($hashes_iterator as $hash)
10360 $value = null;
10361 $algo = null;
10362 if (isset($hash['data']))
10364 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10366 if (isset($hash['attribs']['']['algo']))
10368 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10370 else
10372 $algo = 'md5';
10374 $hashes_parent[] = $algo.':'.$value;
10377 elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
10379 foreach ($hashes_iterator as $hash)
10381 $value = null;
10382 $algo = null;
10383 if (isset($hash['data']))
10385 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10387 if (isset($hash['attribs']['']['algo']))
10389 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10391 else
10393 $algo = 'md5';
10395 $hashes_parent[] = $algo.':'.$value;
10398 if (is_array($hashes_parent))
10400 $hashes_parent = array_values(array_unique($hashes_parent));
10403 // KEYWORDS
10404 if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
10406 if (isset($keywords[0]['data']))
10408 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10409 foreach ($temp as $word)
10411 $keywords_parent[] = trim($word);
10414 unset($temp);
10416 elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10418 if (isset($keywords[0]['data']))
10420 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10421 foreach ($temp as $word)
10423 $keywords_parent[] = trim($word);
10426 unset($temp);
10428 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
10430 if (isset($keywords[0]['data']))
10432 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10433 foreach ($temp as $word)
10435 $keywords_parent[] = trim($word);
10438 unset($temp);
10440 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10442 if (isset($keywords[0]['data']))
10444 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10445 foreach ($temp as $word)
10447 $keywords_parent[] = trim($word);
10450 unset($temp);
10452 if (is_array($keywords_parent))
10454 $keywords_parent = array_values(array_unique($keywords_parent));
10457 // PLAYER
10458 if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
10460 if (isset($player_parent[0]['attribs']['']['url']))
10462 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10465 elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
10467 if (isset($player_parent[0]['attribs']['']['url']))
10469 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10473 // RATINGS
10474 if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
10476 foreach ($ratings as $rating)
10478 $rating_scheme = null;
10479 $rating_value = null;
10480 if (isset($rating['attribs']['']['scheme']))
10482 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10484 else
10486 $rating_scheme = 'urn:simple';
10488 if (isset($rating['data']))
10490 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10492 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10495 elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
10497 foreach ($ratings as $rating)
10499 $rating_scheme = 'urn:itunes';
10500 $rating_value = null;
10501 if (isset($rating['data']))
10503 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10505 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10508 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
10510 foreach ($ratings as $rating)
10512 $rating_scheme = null;
10513 $rating_value = null;
10514 if (isset($rating['attribs']['']['scheme']))
10516 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10518 else
10520 $rating_scheme = 'urn:simple';
10522 if (isset($rating['data']))
10524 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10526 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10529 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
10531 foreach ($ratings as $rating)
10533 $rating_scheme = 'urn:itunes';
10534 $rating_value = null;
10535 if (isset($rating['data']))
10537 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10539 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10542 if (is_array($ratings_parent))
10544 $ratings_parent = array_values(array_unique($ratings_parent));
10547 // RESTRICTIONS
10548 if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
10550 foreach ($restrictions as $restriction)
10552 $restriction_relationship = null;
10553 $restriction_type = null;
10554 $restriction_value = null;
10555 if (isset($restriction['attribs']['']['relationship']))
10557 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
10559 if (isset($restriction['attribs']['']['type']))
10561 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10563 if (isset($restriction['data']))
10565 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10567 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10570 elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10572 foreach ($restrictions as $restriction)
10574 $restriction_relationship = 'allow';
10575 $restriction_type = null;
10576 $restriction_value = 'itunes';
10577 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
10579 $restriction_relationship = 'deny';
10581 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10584 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
10586 foreach ($restrictions as $restriction)
10588 $restriction_relationship = null;
10589 $restriction_type = null;
10590 $restriction_value = null;
10591 if (isset($restriction['attribs']['']['relationship']))
10593 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
10595 if (isset($restriction['attribs']['']['type']))
10597 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10599 if (isset($restriction['data']))
10601 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10603 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10606 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10608 foreach ($restrictions as $restriction)
10610 $restriction_relationship = 'allow';
10611 $restriction_type = null;
10612 $restriction_value = 'itunes';
10613 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
10615 $restriction_relationship = 'deny';
10617 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10620 if (is_array($restrictions_parent))
10622 $restrictions_parent = array_values(array_unique($restrictions_parent));
10624 else
10626 $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
10629 // THUMBNAILS
10630 if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
10632 foreach ($thumbnails as $thumbnail)
10634 if (isset($thumbnail['attribs']['']['url']))
10636 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10640 elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
10642 foreach ($thumbnails as $thumbnail)
10644 if (isset($thumbnail['attribs']['']['url']))
10646 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10651 // TITLES
10652 if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10654 if (isset($title_parent[0]['data']))
10656 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10659 elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10661 if (isset($title_parent[0]['data']))
10663 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10667 // Clear the memory
10668 unset($parent);
10670 // Attributes
10671 $bitrate = null;
10672 $channels = null;
10673 $duration = null;
10674 $expression = null;
10675 $framerate = null;
10676 $height = null;
10677 $javascript = null;
10678 $lang = null;
10679 $length = null;
10680 $medium = null;
10681 $samplingrate = null;
10682 $type = null;
10683 $url = null;
10684 $width = null;
10686 // Elements
10687 $captions = null;
10688 $categories = null;
10689 $copyrights = null;
10690 $credits = null;
10691 $description = null;
10692 $hashes = null;
10693 $keywords = null;
10694 $player = null;
10695 $ratings = null;
10696 $restrictions = null;
10697 $thumbnails = null;
10698 $title = null;
10700 // If we have media:group tags, loop through them.
10701 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
10703 if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
10705 // If we have media:content tags, loop through them.
10706 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
10708 if (isset($content['attribs']['']['url']))
10710 // Attributes
10711 $bitrate = null;
10712 $channels = null;
10713 $duration = null;
10714 $expression = null;
10715 $framerate = null;
10716 $height = null;
10717 $javascript = null;
10718 $lang = null;
10719 $length = null;
10720 $medium = null;
10721 $samplingrate = null;
10722 $type = null;
10723 $url = null;
10724 $width = null;
10726 // Elements
10727 $captions = null;
10728 $categories = null;
10729 $copyrights = null;
10730 $credits = null;
10731 $description = null;
10732 $hashes = null;
10733 $keywords = null;
10734 $player = null;
10735 $ratings = null;
10736 $restrictions = null;
10737 $thumbnails = null;
10738 $title = null;
10740 // Start checking the attributes of media:content
10741 if (isset($content['attribs']['']['bitrate']))
10743 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10745 if (isset($content['attribs']['']['channels']))
10747 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
10749 if (isset($content['attribs']['']['duration']))
10751 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
10753 else
10755 $duration = $duration_parent;
10757 if (isset($content['attribs']['']['expression']))
10759 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
10761 if (isset($content['attribs']['']['framerate']))
10763 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
10765 if (isset($content['attribs']['']['height']))
10767 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
10769 if (isset($content['attribs']['']['lang']))
10771 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10773 if (isset($content['attribs']['']['fileSize']))
10775 $length = ceil($content['attribs']['']['fileSize']);
10777 if (isset($content['attribs']['']['medium']))
10779 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
10781 if (isset($content['attribs']['']['samplingrate']))
10783 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10785 if (isset($content['attribs']['']['type']))
10787 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10789 if (isset($content['attribs']['']['width']))
10791 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
10793 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10795 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
10797 // CAPTIONS
10798 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10800 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10802 $caption_type = null;
10803 $caption_lang = null;
10804 $caption_startTime = null;
10805 $caption_endTime = null;
10806 $caption_text = null;
10807 if (isset($caption['attribs']['']['type']))
10809 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10811 if (isset($caption['attribs']['']['lang']))
10813 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10815 if (isset($caption['attribs']['']['start']))
10817 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10819 if (isset($caption['attribs']['']['end']))
10821 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10823 if (isset($caption['data']))
10825 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10827 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10829 if (is_array($captions))
10831 $captions = array_values(array_unique($captions));
10834 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10836 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10838 $caption_type = null;
10839 $caption_lang = null;
10840 $caption_startTime = null;
10841 $caption_endTime = null;
10842 $caption_text = null;
10843 if (isset($caption['attribs']['']['type']))
10845 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10847 if (isset($caption['attribs']['']['lang']))
10849 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10851 if (isset($caption['attribs']['']['start']))
10853 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10855 if (isset($caption['attribs']['']['end']))
10857 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10859 if (isset($caption['data']))
10861 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10863 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10865 if (is_array($captions))
10867 $captions = array_values(array_unique($captions));
10870 else
10872 $captions = $captions_parent;
10875 // CATEGORIES
10876 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10878 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10880 $term = null;
10881 $scheme = null;
10882 $label = null;
10883 if (isset($category['data']))
10885 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10887 if (isset($category['attribs']['']['scheme']))
10889 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10891 else
10893 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10895 if (isset($category['attribs']['']['label']))
10897 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10899 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10902 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10904 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10906 $term = null;
10907 $scheme = null;
10908 $label = null;
10909 if (isset($category['data']))
10911 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10913 if (isset($category['attribs']['']['scheme']))
10915 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10917 else
10919 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10921 if (isset($category['attribs']['']['label']))
10923 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10925 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10928 if (is_array($categories) && is_array($categories_parent))
10930 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
10932 elseif (is_array($categories))
10934 $categories = array_values(array_unique($categories));
10936 elseif (is_array($categories_parent))
10938 $categories = array_values(array_unique($categories_parent));
10941 // COPYRIGHTS
10942 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10944 $copyright_url = null;
10945 $copyright_label = null;
10946 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10948 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10950 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10952 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10954 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10956 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10958 $copyright_url = null;
10959 $copyright_label = null;
10960 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10962 $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10964 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10966 $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10968 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10970 else
10972 $copyrights = $copyrights_parent;
10975 // CREDITS
10976 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
10978 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
10980 $credit_role = null;
10981 $credit_scheme = null;
10982 $credit_name = null;
10983 if (isset($credit['attribs']['']['role']))
10985 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10987 if (isset($credit['attribs']['']['scheme']))
10989 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10991 else
10993 $credit_scheme = 'urn:ebu';
10995 if (isset($credit['data']))
10997 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10999 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11001 if (is_array($credits))
11003 $credits = array_values(array_unique($credits));
11006 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11008 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11010 $credit_role = null;
11011 $credit_scheme = null;
11012 $credit_name = null;
11013 if (isset($credit['attribs']['']['role']))
11015 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11017 if (isset($credit['attribs']['']['scheme']))
11019 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11021 else
11023 $credit_scheme = 'urn:ebu';
11025 if (isset($credit['data']))
11027 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11029 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11031 if (is_array($credits))
11033 $credits = array_values(array_unique($credits));
11036 else
11038 $credits = $credits_parent;
11041 // DESCRIPTION
11042 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11044 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11046 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11048 $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11050 else
11052 $description = $description_parent;
11055 // HASHES
11056 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11058 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11060 $value = null;
11061 $algo = null;
11062 if (isset($hash['data']))
11064 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11066 if (isset($hash['attribs']['']['algo']))
11068 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11070 else
11072 $algo = 'md5';
11074 $hashes[] = $algo.':'.$value;
11076 if (is_array($hashes))
11078 $hashes = array_values(array_unique($hashes));
11081 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11083 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11085 $value = null;
11086 $algo = null;
11087 if (isset($hash['data']))
11089 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11091 if (isset($hash['attribs']['']['algo']))
11093 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11095 else
11097 $algo = 'md5';
11099 $hashes[] = $algo.':'.$value;
11101 if (is_array($hashes))
11103 $hashes = array_values(array_unique($hashes));
11106 else
11108 $hashes = $hashes_parent;
11111 // KEYWORDS
11112 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11114 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11116 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11117 foreach ($temp as $word)
11119 $keywords[] = trim($word);
11121 unset($temp);
11123 if (is_array($keywords))
11125 $keywords = array_values(array_unique($keywords));
11128 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11130 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11132 $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11133 foreach ($temp as $word)
11135 $keywords[] = trim($word);
11137 unset($temp);
11139 if (is_array($keywords))
11141 $keywords = array_values(array_unique($keywords));
11144 else
11146 $keywords = $keywords_parent;
11149 // PLAYER
11150 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11152 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11154 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11156 $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11158 else
11160 $player = $player_parent;
11163 // RATINGS
11164 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11166 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11168 $rating_scheme = null;
11169 $rating_value = null;
11170 if (isset($rating['attribs']['']['scheme']))
11172 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11174 else
11176 $rating_scheme = 'urn:simple';
11178 if (isset($rating['data']))
11180 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11182 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11184 if (is_array($ratings))
11186 $ratings = array_values(array_unique($ratings));
11189 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11191 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11193 $rating_scheme = null;
11194 $rating_value = null;
11195 if (isset($rating['attribs']['']['scheme']))
11197 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11199 else
11201 $rating_scheme = 'urn:simple';
11203 if (isset($rating['data']))
11205 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11207 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11209 if (is_array($ratings))
11211 $ratings = array_values(array_unique($ratings));
11214 else
11216 $ratings = $ratings_parent;
11219 // RESTRICTIONS
11220 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11222 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11224 $restriction_relationship = null;
11225 $restriction_type = null;
11226 $restriction_value = null;
11227 if (isset($restriction['attribs']['']['relationship']))
11229 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11231 if (isset($restriction['attribs']['']['type']))
11233 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11235 if (isset($restriction['data']))
11237 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11239 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11241 if (is_array($restrictions))
11243 $restrictions = array_values(array_unique($restrictions));
11246 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11248 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11250 $restriction_relationship = null;
11251 $restriction_type = null;
11252 $restriction_value = null;
11253 if (isset($restriction['attribs']['']['relationship']))
11255 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11257 if (isset($restriction['attribs']['']['type']))
11259 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11261 if (isset($restriction['data']))
11263 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11265 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11267 if (is_array($restrictions))
11269 $restrictions = array_values(array_unique($restrictions));
11272 else
11274 $restrictions = $restrictions_parent;
11277 // THUMBNAILS
11278 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11280 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11282 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11284 if (is_array($thumbnails))
11286 $thumbnails = array_values(array_unique($thumbnails));
11289 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11291 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11293 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11295 if (is_array($thumbnails))
11297 $thumbnails = array_values(array_unique($thumbnails));
11300 else
11302 $thumbnails = $thumbnails_parent;
11305 // TITLES
11306 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11308 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11310 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11312 $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11314 else
11316 $title = $title_parent;
11319 $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));
11325 // If we have standalone media:content tags, loop through them.
11326 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
11328 foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
11330 if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11332 // Attributes
11333 $bitrate = null;
11334 $channels = null;
11335 $duration = null;
11336 $expression = null;
11337 $framerate = null;
11338 $height = null;
11339 $javascript = null;
11340 $lang = null;
11341 $length = null;
11342 $medium = null;
11343 $samplingrate = null;
11344 $type = null;
11345 $url = null;
11346 $width = null;
11348 // Elements
11349 $captions = null;
11350 $categories = null;
11351 $copyrights = null;
11352 $credits = null;
11353 $description = null;
11354 $hashes = null;
11355 $keywords = null;
11356 $player = null;
11357 $ratings = null;
11358 $restrictions = null;
11359 $thumbnails = null;
11360 $title = null;
11362 // Start checking the attributes of media:content
11363 if (isset($content['attribs']['']['bitrate']))
11365 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11367 if (isset($content['attribs']['']['channels']))
11369 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
11371 if (isset($content['attribs']['']['duration']))
11373 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
11375 else
11377 $duration = $duration_parent;
11379 if (isset($content['attribs']['']['expression']))
11381 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
11383 if (isset($content['attribs']['']['framerate']))
11385 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
11387 if (isset($content['attribs']['']['height']))
11389 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
11391 if (isset($content['attribs']['']['lang']))
11393 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11395 if (isset($content['attribs']['']['fileSize']))
11397 $length = ceil($content['attribs']['']['fileSize']);
11399 if (isset($content['attribs']['']['medium']))
11401 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
11403 if (isset($content['attribs']['']['samplingrate']))
11405 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11407 if (isset($content['attribs']['']['type']))
11409 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11411 if (isset($content['attribs']['']['width']))
11413 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
11415 if (isset($content['attribs']['']['url']))
11417 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11419 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
11421 // CAPTIONS
11422 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
11424 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
11426 $caption_type = null;
11427 $caption_lang = null;
11428 $caption_startTime = null;
11429 $caption_endTime = null;
11430 $caption_text = null;
11431 if (isset($caption['attribs']['']['type']))
11433 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11435 if (isset($caption['attribs']['']['lang']))
11437 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11439 if (isset($caption['attribs']['']['start']))
11441 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
11443 if (isset($caption['attribs']['']['end']))
11445 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
11447 if (isset($caption['data']))
11449 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11451 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
11453 if (is_array($captions))
11455 $captions = array_values(array_unique($captions));
11458 else
11460 $captions = $captions_parent;
11463 // CATEGORIES
11464 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
11466 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
11468 $term = null;
11469 $scheme = null;
11470 $label = null;
11471 if (isset($category['data']))
11473 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11475 if (isset($category['attribs']['']['scheme']))
11477 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11479 else
11481 $scheme = 'http://search.yahoo.com/mrss/category_schema';
11483 if (isset($category['attribs']['']['label']))
11485 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
11487 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
11490 if (is_array($categories) && is_array($categories_parent))
11492 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
11494 elseif (is_array($categories))
11496 $categories = array_values(array_unique($categories));
11498 elseif (is_array($categories_parent))
11500 $categories = array_values(array_unique($categories_parent));
11502 else
11504 $categories = null;
11507 // COPYRIGHTS
11508 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
11510 $copyright_url = null;
11511 $copyright_label = null;
11512 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
11514 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
11516 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
11518 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11520 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
11522 else
11524 $copyrights = $copyrights_parent;
11527 // CREDITS
11528 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11530 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11532 $credit_role = null;
11533 $credit_scheme = null;
11534 $credit_name = null;
11535 if (isset($credit['attribs']['']['role']))
11537 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11539 if (isset($credit['attribs']['']['scheme']))
11541 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11543 else
11545 $credit_scheme = 'urn:ebu';
11547 if (isset($credit['data']))
11549 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11551 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11553 if (is_array($credits))
11555 $credits = array_values(array_unique($credits));
11558 else
11560 $credits = $credits_parent;
11563 // DESCRIPTION
11564 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11566 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11568 else
11570 $description = $description_parent;
11573 // HASHES
11574 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11576 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11578 $value = null;
11579 $algo = null;
11580 if (isset($hash['data']))
11582 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11584 if (isset($hash['attribs']['']['algo']))
11586 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11588 else
11590 $algo = 'md5';
11592 $hashes[] = $algo.':'.$value;
11594 if (is_array($hashes))
11596 $hashes = array_values(array_unique($hashes));
11599 else
11601 $hashes = $hashes_parent;
11604 // KEYWORDS
11605 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11607 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11609 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11610 foreach ($temp as $word)
11612 $keywords[] = trim($word);
11614 unset($temp);
11616 if (is_array($keywords))
11618 $keywords = array_values(array_unique($keywords));
11621 else
11623 $keywords = $keywords_parent;
11626 // PLAYER
11627 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11629 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11631 else
11633 $player = $player_parent;
11636 // RATINGS
11637 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11639 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11641 $rating_scheme = null;
11642 $rating_value = null;
11643 if (isset($rating['attribs']['']['scheme']))
11645 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11647 else
11649 $rating_scheme = 'urn:simple';
11651 if (isset($rating['data']))
11653 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11655 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11657 if (is_array($ratings))
11659 $ratings = array_values(array_unique($ratings));
11662 else
11664 $ratings = $ratings_parent;
11667 // RESTRICTIONS
11668 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11670 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11672 $restriction_relationship = null;
11673 $restriction_type = null;
11674 $restriction_value = null;
11675 if (isset($restriction['attribs']['']['relationship']))
11677 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11679 if (isset($restriction['attribs']['']['type']))
11681 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11683 if (isset($restriction['data']))
11685 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11687 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11689 if (is_array($restrictions))
11691 $restrictions = array_values(array_unique($restrictions));
11694 else
11696 $restrictions = $restrictions_parent;
11699 // THUMBNAILS
11700 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11702 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11704 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11706 if (is_array($thumbnails))
11708 $thumbnails = array_values(array_unique($thumbnails));
11711 else
11713 $thumbnails = $thumbnails_parent;
11716 // TITLES
11717 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11719 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11721 else
11723 $title = $title_parent;
11726 $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));
11731 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
11733 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11735 // Attributes
11736 $bitrate = null;
11737 $channels = null;
11738 $duration = null;
11739 $expression = null;
11740 $framerate = null;
11741 $height = null;
11742 $javascript = null;
11743 $lang = null;
11744 $length = null;
11745 $medium = null;
11746 $samplingrate = null;
11747 $type = null;
11748 $url = null;
11749 $width = null;
11751 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11752 if (isset($link['attribs']['']['type']))
11754 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11756 if (isset($link['attribs']['']['length']))
11758 $length = ceil($link['attribs']['']['length']);
11761 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11762 $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));
11766 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
11768 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11770 // Attributes
11771 $bitrate = null;
11772 $channels = null;
11773 $duration = null;
11774 $expression = null;
11775 $framerate = null;
11776 $height = null;
11777 $javascript = null;
11778 $lang = null;
11779 $length = null;
11780 $medium = null;
11781 $samplingrate = null;
11782 $type = null;
11783 $url = null;
11784 $width = null;
11786 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11787 if (isset($link['attribs']['']['type']))
11789 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11791 if (isset($link['attribs']['']['length']))
11793 $length = ceil($link['attribs']['']['length']);
11796 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11797 $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));
11801 if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
11803 if (isset($enclosure[0]['attribs']['']['url']))
11805 // Attributes
11806 $bitrate = null;
11807 $channels = null;
11808 $duration = null;
11809 $expression = null;
11810 $framerate = null;
11811 $height = null;
11812 $javascript = null;
11813 $lang = null;
11814 $length = null;
11815 $medium = null;
11816 $samplingrate = null;
11817 $type = null;
11818 $url = null;
11819 $width = null;
11821 $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
11822 if (isset($enclosure[0]['attribs']['']['type']))
11824 $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11826 if (isset($enclosure[0]['attribs']['']['length']))
11828 $length = ceil($enclosure[0]['attribs']['']['length']);
11831 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11832 $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));
11836 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))
11838 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11839 $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));
11842 $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
11844 if (!empty($this->data['enclosures']))
11846 return $this->data['enclosures'];
11848 else
11850 return null;
11855 * Get the latitude coordinates for the item
11857 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
11859 * Uses `<geo:lat>` or `<georss:point>`
11861 * @since 1.0
11862 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11863 * @link http://www.georss.org/ GeoRSS
11864 * @return string|null
11866 public function get_latitude()
11868 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
11870 return (float) $return[0]['data'];
11872 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))
11874 return (float) $match[1];
11876 else
11878 return null;
11883 * Get the longitude coordinates for the item
11885 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
11887 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
11889 * @since 1.0
11890 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11891 * @link http://www.georss.org/ GeoRSS
11892 * @return string|null
11894 public function get_longitude()
11896 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
11898 return (float) $return[0]['data'];
11900 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
11902 return (float) $return[0]['data'];
11904 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))
11906 return (float) $match[2];
11908 else
11910 return null;
11915 * Get the `<atom:source>` for the item
11917 * @since 1.1
11918 * @return SimplePie_Source|null
11920 public function get_source()
11922 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
11924 return $this->registry->create('Source', array($this, $return[0]));
11926 else
11928 return null;
11934 * Used for feed auto-discovery
11937 * This class can be overloaded with {@see SimplePie::set_locator_class()}
11939 * @package SimplePie
11941 class SimplePie_Locator
11943 var $useragent;
11944 var $timeout;
11945 var $file;
11946 var $local = array();
11947 var $elsewhere = array();
11948 var $cached_entities = array();
11949 var $http_base;
11950 var $base;
11951 var $base_location = 0;
11952 var $checked_feeds = 0;
11953 var $max_checked_feeds = 10;
11954 protected $registry;
11956 public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
11958 $this->file = $file;
11959 $this->useragent = $useragent;
11960 $this->timeout = $timeout;
11961 $this->max_checked_feeds = $max_checked_feeds;
11963 if (class_exists('DOMDocument'))
11965 $this->dom = new DOMDocument();
11967 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
11968 $this->dom->loadHTML($this->file->body);
11969 restore_error_handler();
11971 else
11973 $this->dom = null;
11977 public function set_registry(SimplePie_Registry $registry)
11979 $this->registry = $registry;
11982 public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
11984 if ($this->is_feed($this->file))
11986 return $this->file;
11989 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
11991 $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
11992 if ($sniffer->get_type() !== 'text/html')
11994 return null;
11998 if ($type & ~SIMPLEPIE_LOCATOR_NONE)
12000 $this->get_base();
12003 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
12005 return $working[0];
12008 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
12010 if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
12012 return $working;
12015 if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
12017 return $working;
12020 if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
12022 return $working;
12025 if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
12027 return $working;
12030 return null;
12033 public function is_feed($file)
12035 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
12037 $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
12038 $sniffed = $sniffer->get_type();
12039 if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
12041 return true;
12043 else
12045 return false;
12048 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
12050 return true;
12052 else
12054 return false;
12058 public function get_base()
12060 if ($this->dom === null)
12062 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12064 $this->http_base = $this->file->url;
12065 $this->base = $this->http_base;
12066 $elements = $this->dom->getElementsByTagName('base');
12067 foreach ($elements as $element)
12069 if ($element->hasAttribute('href'))
12071 $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
12072 if ($base === false)
12074 continue;
12076 $this->base = $base;
12077 $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
12078 break;
12083 public function autodiscovery()
12085 $done = array();
12086 $feeds = array();
12087 $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
12088 $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
12089 $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
12091 if (!empty($feeds))
12093 return array_values($feeds);
12095 else
12097 return null;
12101 protected function search_elements_by_tag($name, &$done, $feeds)
12103 if ($this->dom === null)
12105 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12108 $links = $this->dom->getElementsByTagName($name);
12109 foreach ($links as $link)
12111 if ($this->checked_feeds === $this->max_checked_feeds)
12113 break;
12115 if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
12117 $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
12118 $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
12120 if ($this->base_location < $line)
12122 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12124 else
12126 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12128 if ($href === false)
12130 continue;
12133 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]))
12135 $this->checked_feeds++;
12136 $headers = array(
12137 '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',
12139 $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
12140 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))
12142 $feeds[$href] = $feed;
12145 $done[] = $href;
12149 return $feeds;
12152 public function get_links()
12154 if ($this->dom === null)
12156 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12159 $links = $this->dom->getElementsByTagName('a');
12160 foreach ($links as $link)
12162 if ($link->hasAttribute('href'))
12164 $href = trim($link->getAttribute('href'));
12165 $parsed = $this->registry->call('Misc', 'parse_url', array($href));
12166 if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
12168 if ($this->base_location < $link->getLineNo())
12170 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12172 else
12174 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12176 if ($href === false)
12178 continue;
12181 $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
12183 if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
12185 $this->local[] = $href;
12187 else
12189 $this->elsewhere[] = $href;
12194 $this->local = array_unique($this->local);
12195 $this->elsewhere = array_unique($this->elsewhere);
12196 if (!empty($this->local) || !empty($this->elsewhere))
12198 return true;
12200 return null;
12203 public function extension(&$array)
12205 foreach ($array as $key => $value)
12207 if ($this->checked_feeds === $this->max_checked_feeds)
12209 break;
12211 if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
12213 $this->checked_feeds++;
12215 $headers = array(
12216 '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',
12218 $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
12219 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))
12221 return $feed;
12223 else
12225 unset($array[$key]);
12229 return null;
12232 public function body(&$array)
12234 foreach ($array as $key => $value)
12236 if ($this->checked_feeds === $this->max_checked_feeds)
12238 break;
12240 if (preg_match('/(rss|rdf|atom|xml)/i', $value))
12242 $this->checked_feeds++;
12243 $headers = array(
12244 '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',
12246 $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
12247 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))
12249 return $feed;
12251 else
12253 unset($array[$key]);
12257 return null;
12262 * Miscellanous utilities
12264 * @package SimplePie
12266 class SimplePie_Misc
12268 public static function time_hms($seconds)
12270 $time = '';
12272 $hours = floor($seconds / 3600);
12273 $remainder = $seconds % 3600;
12274 if ($hours > 0)
12276 $time .= $hours.':';
12279 $minutes = floor($remainder / 60);
12280 $seconds = $remainder % 60;
12281 if ($minutes < 10 && $hours > 0)
12283 $minutes = '0' . $minutes;
12285 if ($seconds < 10)
12287 $seconds = '0' . $seconds;
12290 $time .= $minutes.':';
12291 $time .= $seconds;
12293 return $time;
12296 public static function absolutize_url($relative, $base)
12298 $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
12299 if ($iri === false)
12301 return false;
12303 return $iri->get_uri();
12307 * Get a HTML/XML element from a HTML string
12309 * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
12310 * @param string $realname Element name (including namespace prefix if applicable)
12311 * @param string $string HTML document
12312 * @return array
12314 public static function get_element($realname, $string)
12316 $return = array();
12317 $name = preg_quote($realname, '/');
12318 if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
12320 for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
12322 $return[$i]['tag'] = $realname;
12323 $return[$i]['full'] = $matches[$i][0][0];
12324 $return[$i]['offset'] = $matches[$i][0][1];
12325 if (strlen($matches[$i][3][0]) <= 2)
12327 $return[$i]['self_closing'] = true;
12329 else
12331 $return[$i]['self_closing'] = false;
12332 $return[$i]['content'] = $matches[$i][4][0];
12334 $return[$i]['attribs'] = array();
12335 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))
12337 for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
12339 if (count($attribs[$j]) === 2)
12341 $attribs[$j][2] = $attribs[$j][1];
12343 $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
12348 return $return;
12351 public static function element_implode($element)
12353 $full = "<$element[tag]";
12354 foreach ($element['attribs'] as $key => $value)
12356 $key = strtolower($key);
12357 $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
12359 if ($element['self_closing'])
12361 $full .= ' />';
12363 else
12365 $full .= ">$element[content]</$element[tag]>";
12367 return $full;
12370 public static function error($message, $level, $file, $line)
12372 if ((ini_get('error_reporting') & $level) > 0)
12374 switch ($level)
12376 case E_USER_ERROR:
12377 $note = 'PHP Error';
12378 break;
12379 case E_USER_WARNING:
12380 $note = 'PHP Warning';
12381 break;
12382 case E_USER_NOTICE:
12383 $note = 'PHP Notice';
12384 break;
12385 default:
12386 $note = 'Unknown Error';
12387 break;
12390 $log_error = true;
12391 if (!function_exists('error_log'))
12393 $log_error = false;
12396 $log_file = @ini_get('error_log');
12397 if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
12399 $log_error = false;
12402 if ($log_error)
12404 @error_log("$note: $message in $file on line $line", 0);
12408 return $message;
12411 public static function fix_protocol($url, $http = 1)
12413 $url = SimplePie_Misc::normalize_url($url);
12414 $parsed = SimplePie_Misc::parse_url($url);
12415 if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
12417 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
12420 if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
12422 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
12425 if ($http === 2 && $parsed['scheme'] !== '')
12427 return "feed:$url";
12429 elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
12431 return substr_replace($url, 'podcast', 0, 4);
12433 elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
12435 return substr_replace($url, 'itpc', 0, 4);
12437 else
12439 return $url;
12443 public static function parse_url($url)
12445 $iri = new SimplePie_IRI($url);
12446 return array(
12447 'scheme' => (string) $iri->scheme,
12448 'authority' => (string) $iri->authority,
12449 'path' => (string) $iri->path,
12450 'query' => (string) $iri->query,
12451 'fragment' => (string) $iri->fragment
12455 public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
12457 $iri = new SimplePie_IRI('');
12458 $iri->scheme = $scheme;
12459 $iri->authority = $authority;
12460 $iri->path = $path;
12461 $iri->query = $query;
12462 $iri->fragment = $fragment;
12463 return $iri->get_uri();
12466 public static function normalize_url($url)
12468 $iri = new SimplePie_IRI($url);
12469 return $iri->get_uri();
12472 public static function percent_encoding_normalization($match)
12474 $integer = hexdec($match[1]);
12475 if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
12477 return chr($integer);
12479 else
12481 return strtoupper($match[0]);
12486 * Converts a Windows-1252 encoded string to a UTF-8 encoded string
12488 * @static
12489 * @param string $string Windows-1252 encoded string
12490 * @return string UTF-8 encoded string
12492 public static function windows_1252_to_utf8($string)
12494 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");
12496 return strtr($string, $convert_table);
12500 * Change a string from one encoding to another
12502 * @param string $data Raw data in $input encoding
12503 * @param string $input Encoding of $data
12504 * @param string $output Encoding you want
12505 * @return string|boolean False if we can't convert it
12507 public static function change_encoding($data, $input, $output)
12509 $input = SimplePie_Misc::encoding($input);
12510 $output = SimplePie_Misc::encoding($output);
12512 // We fail to fail on non US-ASCII bytes
12513 if ($input === 'US-ASCII')
12515 static $non_ascii_octects = '';
12516 if (!$non_ascii_octects)
12518 for ($i = 0x80; $i <= 0xFF; $i++)
12520 $non_ascii_octects .= chr($i);
12523 $data = substr($data, 0, strcspn($data, $non_ascii_octects));
12526 // This is first, as behaviour of this is completely predictable
12527 if ($input === 'windows-1252' && $output === 'UTF-8')
12529 return SimplePie_Misc::windows_1252_to_utf8($data);
12531 // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
12532 elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
12534 return $return;
12536 // This is last, as behaviour of this varies with OS userland and PHP version
12537 elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
12539 return $return;
12541 // If we can't do anything, just fail
12542 else
12544 return false;
12548 protected static function change_encoding_mbstring($data, $input, $output)
12550 if ($input === 'windows-949')
12552 $input = 'EUC-KR';
12554 if ($output === 'windows-949')
12556 $output = 'EUC-KR';
12558 if ($input === 'Windows-31J')
12560 $input = 'SJIS';
12562 if ($output === 'Windows-31J')
12564 $output = 'SJIS';
12567 // Check that the encoding is supported
12568 if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
12570 return false;
12572 if (!in_array($input, mb_list_encodings()))
12574 return false;
12577 // Let's do some conversion
12578 if ($return = @mb_convert_encoding($data, $output, $input))
12580 return $return;
12583 return false;
12586 protected static function change_encoding_iconv($data, $input, $output)
12588 return @iconv($input, $output, $data);
12592 * Normalize an encoding name
12594 * This is automatically generated by create.php
12596 * To generate it, run `php create.php` on the command line, and copy the
12597 * output to replace this function.
12599 * @param string $charset Character set to standardise
12600 * @return string Standardised name
12602 public static function encoding($charset)
12604 // Normalization from UTS #22
12605 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
12607 case 'adobestandardencoding':
12608 case 'csadobestandardencoding':
12609 return 'Adobe-Standard-Encoding';
12611 case 'adobesymbolencoding':
12612 case 'cshppsmath':
12613 return 'Adobe-Symbol-Encoding';
12615 case 'ami1251':
12616 case 'amiga1251':
12617 return 'Amiga-1251';
12619 case 'ansix31101983':
12620 case 'csat5001983':
12621 case 'csiso99naplps':
12622 case 'isoir99':
12623 case 'naplps':
12624 return 'ANSI_X3.110-1983';
12626 case 'arabic7':
12627 case 'asmo449':
12628 case 'csiso89asmo449':
12629 case 'iso9036':
12630 case 'isoir89':
12631 return 'ASMO_449';
12633 case 'big5':
12634 case 'csbig5':
12635 return 'Big5';
12637 case 'big5hkscs':
12638 return 'Big5-HKSCS';
12640 case 'bocu1':
12641 case 'csbocu1':
12642 return 'BOCU-1';
12644 case 'brf':
12645 case 'csbrf':
12646 return 'BRF';
12648 case 'bs4730':
12649 case 'csiso4unitedkingdom':
12650 case 'gb':
12651 case 'iso646gb':
12652 case 'isoir4':
12653 case 'uk':
12654 return 'BS_4730';
12656 case 'bsviewdata':
12657 case 'csiso47bsviewdata':
12658 case 'isoir47':
12659 return 'BS_viewdata';
12661 case 'cesu8':
12662 case 'cscesu8':
12663 return 'CESU-8';
12665 case 'ca':
12666 case 'csa71':
12667 case 'csaz243419851':
12668 case 'csiso121canadian1':
12669 case 'iso646ca':
12670 case 'isoir121':
12671 return 'CSA_Z243.4-1985-1';
12673 case 'csa72':
12674 case 'csaz243419852':
12675 case 'csiso122canadian2':
12676 case 'iso646ca2':
12677 case 'isoir122':
12678 return 'CSA_Z243.4-1985-2';
12680 case 'csaz24341985gr':
12681 case 'csiso123csaz24341985gr':
12682 case 'isoir123':
12683 return 'CSA_Z243.4-1985-gr';
12685 case 'csiso139csn369103':
12686 case 'csn369103':
12687 case 'isoir139':
12688 return 'CSN_369103';
12690 case 'csdecmcs':
12691 case 'dec':
12692 case 'decmcs':
12693 return 'DEC-MCS';
12695 case 'csiso21german':
12696 case 'de':
12697 case 'din66003':
12698 case 'iso646de':
12699 case 'isoir21':
12700 return 'DIN_66003';
12702 case 'csdkus':
12703 case 'dkus':
12704 return 'dk-us';
12706 case 'csiso646danish':
12707 case 'dk':
12708 case 'ds2089':
12709 case 'iso646dk':
12710 return 'DS_2089';
12712 case 'csibmebcdicatde':
12713 case 'ebcdicatde':
12714 return 'EBCDIC-AT-DE';
12716 case 'csebcdicatdea':
12717 case 'ebcdicatdea':
12718 return 'EBCDIC-AT-DE-A';
12720 case 'csebcdiccafr':
12721 case 'ebcdiccafr':
12722 return 'EBCDIC-CA-FR';
12724 case 'csebcdicdkno':
12725 case 'ebcdicdkno':
12726 return 'EBCDIC-DK-NO';
12728 case 'csebcdicdknoa':
12729 case 'ebcdicdknoa':
12730 return 'EBCDIC-DK-NO-A';
12732 case 'csebcdices':
12733 case 'ebcdices':
12734 return 'EBCDIC-ES';
12736 case 'csebcdicesa':
12737 case 'ebcdicesa':
12738 return 'EBCDIC-ES-A';
12740 case 'csebcdicess':
12741 case 'ebcdicess':
12742 return 'EBCDIC-ES-S';
12744 case 'csebcdicfise':
12745 case 'ebcdicfise':
12746 return 'EBCDIC-FI-SE';
12748 case 'csebcdicfisea':
12749 case 'ebcdicfisea':
12750 return 'EBCDIC-FI-SE-A';
12752 case 'csebcdicfr':
12753 case 'ebcdicfr':
12754 return 'EBCDIC-FR';
12756 case 'csebcdicit':
12757 case 'ebcdicit':
12758 return 'EBCDIC-IT';
12760 case 'csebcdicpt':
12761 case 'ebcdicpt':
12762 return 'EBCDIC-PT';
12764 case 'csebcdicuk':
12765 case 'ebcdicuk':
12766 return 'EBCDIC-UK';
12768 case 'csebcdicus':
12769 case 'ebcdicus':
12770 return 'EBCDIC-US';
12772 case 'csiso111ecmacyrillic':
12773 case 'ecmacyrillic':
12774 case 'isoir111':
12775 case 'koi8e':
12776 return 'ECMA-cyrillic';
12778 case 'csiso17spanish':
12779 case 'es':
12780 case 'iso646es':
12781 case 'isoir17':
12782 return 'ES';
12784 case 'csiso85spanish2':
12785 case 'es2':
12786 case 'iso646es2':
12787 case 'isoir85':
12788 return 'ES2';
12790 case 'cseucpkdfmtjapanese':
12791 case 'eucjp':
12792 case 'extendedunixcodepackedformatforjapanese':
12793 return 'EUC-JP';
12795 case 'cseucfixwidjapanese':
12796 case 'extendedunixcodefixedwidthforjapanese':
12797 return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
12799 case 'gb18030':
12800 return 'GB18030';
12802 case 'chinese':
12803 case 'cp936':
12804 case 'csgb2312':
12805 case 'csiso58gb231280':
12806 case 'gb2312':
12807 case 'gb231280':
12808 case 'gbk':
12809 case 'isoir58':
12810 case 'ms936':
12811 case 'windows936':
12812 return 'GBK';
12814 case 'cn':
12815 case 'csiso57gb1988':
12816 case 'gb198880':
12817 case 'iso646cn':
12818 case 'isoir57':
12819 return 'GB_1988-80';
12821 case 'csiso153gost1976874':
12822 case 'gost1976874':
12823 case 'isoir153':
12824 case 'stsev35888':
12825 return 'GOST_19768-74';
12827 case 'csiso150':
12828 case 'csiso150greekccitt':
12829 case 'greekccitt':
12830 case 'isoir150':
12831 return 'greek-ccitt';
12833 case 'csiso88greek7':
12834 case 'greek7':
12835 case 'isoir88':
12836 return 'greek7';
12838 case 'csiso18greek7old':
12839 case 'greek7old':
12840 case 'isoir18':
12841 return 'greek7-old';
12843 case 'cshpdesktop':
12844 case 'hpdesktop':
12845 return 'HP-DeskTop';
12847 case 'cshplegal':
12848 case 'hplegal':
12849 return 'HP-Legal';
12851 case 'cshpmath8':
12852 case 'hpmath8':
12853 return 'HP-Math8';
12855 case 'cshppifont':
12856 case 'hppifont':
12857 return 'HP-Pi-font';
12859 case 'cshproman8':
12860 case 'hproman8':
12861 case 'r8':
12862 case 'roman8':
12863 return 'hp-roman8';
12865 case 'hzgb2312':
12866 return 'HZ-GB-2312';
12868 case 'csibmsymbols':
12869 case 'ibmsymbols':
12870 return 'IBM-Symbols';
12872 case 'csibmthai':
12873 case 'ibmthai':
12874 return 'IBM-Thai';
12876 case 'cp37':
12877 case 'csibm37':
12878 case 'ebcdiccpca':
12879 case 'ebcdiccpnl':
12880 case 'ebcdiccpus':
12881 case 'ebcdiccpwt':
12882 case 'ibm37':
12883 return 'IBM037';
12885 case 'cp38':
12886 case 'csibm38':
12887 case 'ebcdicint':
12888 case 'ibm38':
12889 return 'IBM038';
12891 case 'cp273':
12892 case 'csibm273':
12893 case 'ibm273':
12894 return 'IBM273';
12896 case 'cp274':
12897 case 'csibm274':
12898 case 'ebcdicbe':
12899 case 'ibm274':
12900 return 'IBM274';
12902 case 'cp275':
12903 case 'csibm275':
12904 case 'ebcdicbr':
12905 case 'ibm275':
12906 return 'IBM275';
12908 case 'csibm277':
12909 case 'ebcdiccpdk':
12910 case 'ebcdiccpno':
12911 case 'ibm277':
12912 return 'IBM277';
12914 case 'cp278':
12915 case 'csibm278':
12916 case 'ebcdiccpfi':
12917 case 'ebcdiccpse':
12918 case 'ibm278':
12919 return 'IBM278';
12921 case 'cp280':
12922 case 'csibm280':
12923 case 'ebcdiccpit':
12924 case 'ibm280':
12925 return 'IBM280';
12927 case 'cp281':
12928 case 'csibm281':
12929 case 'ebcdicjpe':
12930 case 'ibm281':
12931 return 'IBM281';
12933 case 'cp284':
12934 case 'csibm284':
12935 case 'ebcdiccpes':
12936 case 'ibm284':
12937 return 'IBM284';
12939 case 'cp285':
12940 case 'csibm285':
12941 case 'ebcdiccpgb':
12942 case 'ibm285':
12943 return 'IBM285';
12945 case 'cp290':
12946 case 'csibm290':
12947 case 'ebcdicjpkana':
12948 case 'ibm290':
12949 return 'IBM290';
12951 case 'cp297':
12952 case 'csibm297':
12953 case 'ebcdiccpfr':
12954 case 'ibm297':
12955 return 'IBM297';
12957 case 'cp420':
12958 case 'csibm420':
12959 case 'ebcdiccpar1':
12960 case 'ibm420':
12961 return 'IBM420';
12963 case 'cp423':
12964 case 'csibm423':
12965 case 'ebcdiccpgr':
12966 case 'ibm423':
12967 return 'IBM423';
12969 case 'cp424':
12970 case 'csibm424':
12971 case 'ebcdiccphe':
12972 case 'ibm424':
12973 return 'IBM424';
12975 case '437':
12976 case 'cp437':
12977 case 'cspc8codepage437':
12978 case 'ibm437':
12979 return 'IBM437';
12981 case 'cp500':
12982 case 'csibm500':
12983 case 'ebcdiccpbe':
12984 case 'ebcdiccpch':
12985 case 'ibm500':
12986 return 'IBM500';
12988 case 'cp775':
12989 case 'cspc775baltic':
12990 case 'ibm775':
12991 return 'IBM775';
12993 case '850':
12994 case 'cp850':
12995 case 'cspc850multilingual':
12996 case 'ibm850':
12997 return 'IBM850';
12999 case '851':
13000 case 'cp851':
13001 case 'csibm851':
13002 case 'ibm851':
13003 return 'IBM851';
13005 case '852':
13006 case 'cp852':
13007 case 'cspcp852':
13008 case 'ibm852':
13009 return 'IBM852';
13011 case '855':
13012 case 'cp855':
13013 case 'csibm855':
13014 case 'ibm855':
13015 return 'IBM855';
13017 case '857':
13018 case 'cp857':
13019 case 'csibm857':
13020 case 'ibm857':
13021 return 'IBM857';
13023 case 'ccsid858':
13024 case 'cp858':
13025 case 'ibm858':
13026 case 'pcmultilingual850euro':
13027 return 'IBM00858';
13029 case '860':
13030 case 'cp860':
13031 case 'csibm860':
13032 case 'ibm860':
13033 return 'IBM860';
13035 case '861':
13036 case 'cp861':
13037 case 'cpis':
13038 case 'csibm861':
13039 case 'ibm861':
13040 return 'IBM861';
13042 case '862':
13043 case 'cp862':
13044 case 'cspc862latinhebrew':
13045 case 'ibm862':
13046 return 'IBM862';
13048 case '863':
13049 case 'cp863':
13050 case 'csibm863':
13051 case 'ibm863':
13052 return 'IBM863';
13054 case 'cp864':
13055 case 'csibm864':
13056 case 'ibm864':
13057 return 'IBM864';
13059 case '865':
13060 case 'cp865':
13061 case 'csibm865':
13062 case 'ibm865':
13063 return 'IBM865';
13065 case '866':
13066 case 'cp866':
13067 case 'csibm866':
13068 case 'ibm866':
13069 return 'IBM866';
13071 case 'cp868':
13072 case 'cpar':
13073 case 'csibm868':
13074 case 'ibm868':
13075 return 'IBM868';
13077 case '869':
13078 case 'cp869':
13079 case 'cpgr':
13080 case 'csibm869':
13081 case 'ibm869':
13082 return 'IBM869';
13084 case 'cp870':
13085 case 'csibm870':
13086 case 'ebcdiccproece':
13087 case 'ebcdiccpyu':
13088 case 'ibm870':
13089 return 'IBM870';
13091 case 'cp871':
13092 case 'csibm871':
13093 case 'ebcdiccpis':
13094 case 'ibm871':
13095 return 'IBM871';
13097 case 'cp880':
13098 case 'csibm880':
13099 case 'ebcdiccyrillic':
13100 case 'ibm880':
13101 return 'IBM880';
13103 case 'cp891':
13104 case 'csibm891':
13105 case 'ibm891':
13106 return 'IBM891';
13108 case 'cp903':
13109 case 'csibm903':
13110 case 'ibm903':
13111 return 'IBM903';
13113 case '904':
13114 case 'cp904':
13115 case 'csibbm904':
13116 case 'ibm904':
13117 return 'IBM904';
13119 case 'cp905':
13120 case 'csibm905':
13121 case 'ebcdiccptr':
13122 case 'ibm905':
13123 return 'IBM905';
13125 case 'cp918':
13126 case 'csibm918':
13127 case 'ebcdiccpar2':
13128 case 'ibm918':
13129 return 'IBM918';
13131 case 'ccsid924':
13132 case 'cp924':
13133 case 'ebcdiclatin9euro':
13134 case 'ibm924':
13135 return 'IBM00924';
13137 case 'cp1026':
13138 case 'csibm1026':
13139 case 'ibm1026':
13140 return 'IBM1026';
13142 case 'ibm1047':
13143 return 'IBM1047';
13145 case 'ccsid1140':
13146 case 'cp1140':
13147 case 'ebcdicus37euro':
13148 case 'ibm1140':
13149 return 'IBM01140';
13151 case 'ccsid1141':
13152 case 'cp1141':
13153 case 'ebcdicde273euro':
13154 case 'ibm1141':
13155 return 'IBM01141';
13157 case 'ccsid1142':
13158 case 'cp1142':
13159 case 'ebcdicdk277euro':
13160 case 'ebcdicno277euro':
13161 case 'ibm1142':
13162 return 'IBM01142';
13164 case 'ccsid1143':
13165 case 'cp1143':
13166 case 'ebcdicfi278euro':
13167 case 'ebcdicse278euro':
13168 case 'ibm1143':
13169 return 'IBM01143';
13171 case 'ccsid1144':
13172 case 'cp1144':
13173 case 'ebcdicit280euro':
13174 case 'ibm1144':
13175 return 'IBM01144';
13177 case 'ccsid1145':
13178 case 'cp1145':
13179 case 'ebcdices284euro':
13180 case 'ibm1145':
13181 return 'IBM01145';
13183 case 'ccsid1146':
13184 case 'cp1146':
13185 case 'ebcdicgb285euro':
13186 case 'ibm1146':
13187 return 'IBM01146';
13189 case 'ccsid1147':
13190 case 'cp1147':
13191 case 'ebcdicfr297euro':
13192 case 'ibm1147':
13193 return 'IBM01147';
13195 case 'ccsid1148':
13196 case 'cp1148':
13197 case 'ebcdicinternational500euro':
13198 case 'ibm1148':
13199 return 'IBM01148';
13201 case 'ccsid1149':
13202 case 'cp1149':
13203 case 'ebcdicis871euro':
13204 case 'ibm1149':
13205 return 'IBM01149';
13207 case 'csiso143iecp271':
13208 case 'iecp271':
13209 case 'isoir143':
13210 return 'IEC_P27-1';
13212 case 'csiso49inis':
13213 case 'inis':
13214 case 'isoir49':
13215 return 'INIS';
13217 case 'csiso50inis8':
13218 case 'inis8':
13219 case 'isoir50':
13220 return 'INIS-8';
13222 case 'csiso51iniscyrillic':
13223 case 'iniscyrillic':
13224 case 'isoir51':
13225 return 'INIS-cyrillic';
13227 case 'csinvariant':
13228 case 'invariant':
13229 return 'INVARIANT';
13231 case 'iso2022cn':
13232 return 'ISO-2022-CN';
13234 case 'iso2022cnext':
13235 return 'ISO-2022-CN-EXT';
13237 case 'csiso2022jp':
13238 case 'iso2022jp':
13239 return 'ISO-2022-JP';
13241 case 'csiso2022jp2':
13242 case 'iso2022jp2':
13243 return 'ISO-2022-JP-2';
13245 case 'csiso2022kr':
13246 case 'iso2022kr':
13247 return 'ISO-2022-KR';
13249 case 'cswindows30latin1':
13250 case 'iso88591windows30latin1':
13251 return 'ISO-8859-1-Windows-3.0-Latin-1';
13253 case 'cswindows31latin1':
13254 case 'iso88591windows31latin1':
13255 return 'ISO-8859-1-Windows-3.1-Latin-1';
13257 case 'csisolatin2':
13258 case 'iso88592':
13259 case 'iso885921987':
13260 case 'isoir101':
13261 case 'l2':
13262 case 'latin2':
13263 return 'ISO-8859-2';
13265 case 'cswindows31latin2':
13266 case 'iso88592windowslatin2':
13267 return 'ISO-8859-2-Windows-Latin-2';
13269 case 'csisolatin3':
13270 case 'iso88593':
13271 case 'iso885931988':
13272 case 'isoir109':
13273 case 'l3':
13274 case 'latin3':
13275 return 'ISO-8859-3';
13277 case 'csisolatin4':
13278 case 'iso88594':
13279 case 'iso885941988':
13280 case 'isoir110':
13281 case 'l4':
13282 case 'latin4':
13283 return 'ISO-8859-4';
13285 case 'csisolatincyrillic':
13286 case 'cyrillic':
13287 case 'iso88595':
13288 case 'iso885951988':
13289 case 'isoir144':
13290 return 'ISO-8859-5';
13292 case 'arabic':
13293 case 'asmo708':
13294 case 'csisolatinarabic':
13295 case 'ecma114':
13296 case 'iso88596':
13297 case 'iso885961987':
13298 case 'isoir127':
13299 return 'ISO-8859-6';
13301 case 'csiso88596e':
13302 case 'iso88596e':
13303 return 'ISO-8859-6-E';
13305 case 'csiso88596i':
13306 case 'iso88596i':
13307 return 'ISO-8859-6-I';
13309 case 'csisolatingreek':
13310 case 'ecma118':
13311 case 'elot928':
13312 case 'greek':
13313 case 'greek8':
13314 case 'iso88597':
13315 case 'iso885971987':
13316 case 'isoir126':
13317 return 'ISO-8859-7';
13319 case 'csisolatinhebrew':
13320 case 'hebrew':
13321 case 'iso88598':
13322 case 'iso885981988':
13323 case 'isoir138':
13324 return 'ISO-8859-8';
13326 case 'csiso88598e':
13327 case 'iso88598e':
13328 return 'ISO-8859-8-E';
13330 case 'csiso88598i':
13331 case 'iso88598i':
13332 return 'ISO-8859-8-I';
13334 case 'cswindows31latin5':
13335 case 'iso88599windowslatin5':
13336 return 'ISO-8859-9-Windows-Latin-5';
13338 case 'csisolatin6':
13339 case 'iso885910':
13340 case 'iso8859101992':
13341 case 'isoir157':
13342 case 'l6':
13343 case 'latin6':
13344 return 'ISO-8859-10';
13346 case 'iso885913':
13347 return 'ISO-8859-13';
13349 case 'iso885914':
13350 case 'iso8859141998':
13351 case 'isoceltic':
13352 case 'isoir199':
13353 case 'l8':
13354 case 'latin8':
13355 return 'ISO-8859-14';
13357 case 'iso885915':
13358 case 'latin9':
13359 return 'ISO-8859-15';
13361 case 'iso885916':
13362 case 'iso8859162001':
13363 case 'isoir226':
13364 case 'l10':
13365 case 'latin10':
13366 return 'ISO-8859-16';
13368 case 'iso10646j1':
13369 return 'ISO-10646-J-1';
13371 case 'csunicode':
13372 case 'iso10646ucs2':
13373 return 'ISO-10646-UCS-2';
13375 case 'csucs4':
13376 case 'iso10646ucs4':
13377 return 'ISO-10646-UCS-4';
13379 case 'csunicodeascii':
13380 case 'iso10646ucsbasic':
13381 return 'ISO-10646-UCS-Basic';
13383 case 'csunicodelatin1':
13384 case 'iso10646':
13385 case 'iso10646unicodelatin1':
13386 return 'ISO-10646-Unicode-Latin1';
13388 case 'csiso10646utf1':
13389 case 'iso10646utf1':
13390 return 'ISO-10646-UTF-1';
13392 case 'csiso115481':
13393 case 'iso115481':
13394 case 'isotr115481':
13395 return 'ISO-11548-1';
13397 case 'csiso90':
13398 case 'isoir90':
13399 return 'iso-ir-90';
13401 case 'csunicodeibm1261':
13402 case 'isounicodeibm1261':
13403 return 'ISO-Unicode-IBM-1261';
13405 case 'csunicodeibm1264':
13406 case 'isounicodeibm1264':
13407 return 'ISO-Unicode-IBM-1264';
13409 case 'csunicodeibm1265':
13410 case 'isounicodeibm1265':
13411 return 'ISO-Unicode-IBM-1265';
13413 case 'csunicodeibm1268':
13414 case 'isounicodeibm1268':
13415 return 'ISO-Unicode-IBM-1268';
13417 case 'csunicodeibm1276':
13418 case 'isounicodeibm1276':
13419 return 'ISO-Unicode-IBM-1276';
13421 case 'csiso646basic1983':
13422 case 'iso646basic1983':
13423 case 'ref':
13424 return 'ISO_646.basic:1983';
13426 case 'csiso2intlrefversion':
13427 case 'irv':
13428 case 'iso646irv1983':
13429 case 'isoir2':
13430 return 'ISO_646.irv:1983';
13432 case 'csiso2033':
13433 case 'e13b':
13434 case 'iso20331983':
13435 case 'isoir98':
13436 return 'ISO_2033-1983';
13438 case 'csiso5427cyrillic':
13439 case 'iso5427':
13440 case 'isoir37':
13441 return 'ISO_5427';
13443 case 'iso5427cyrillic1981':
13444 case 'iso54271981':
13445 case 'isoir54':
13446 return 'ISO_5427:1981';
13448 case 'csiso5428greek':
13449 case 'iso54281980':
13450 case 'isoir55':
13451 return 'ISO_5428:1980';
13453 case 'csiso6937add':
13454 case 'iso6937225':
13455 case 'isoir152':
13456 return 'ISO_6937-2-25';
13458 case 'csisotextcomm':
13459 case 'iso69372add':
13460 case 'isoir142':
13461 return 'ISO_6937-2-add';
13463 case 'csiso8859supp':
13464 case 'iso8859supp':
13465 case 'isoir154':
13466 case 'latin125':
13467 return 'ISO_8859-supp';
13469 case 'csiso10367box':
13470 case 'iso10367box':
13471 case 'isoir155':
13472 return 'ISO_10367-box';
13474 case 'csiso15italian':
13475 case 'iso646it':
13476 case 'isoir15':
13477 case 'it':
13478 return 'IT';
13480 case 'csiso13jisc6220jp':
13481 case 'isoir13':
13482 case 'jisc62201969':
13483 case 'jisc62201969jp':
13484 case 'katakana':
13485 case 'x2017':
13486 return 'JIS_C6220-1969-jp';
13488 case 'csiso14jisc6220ro':
13489 case 'iso646jp':
13490 case 'isoir14':
13491 case 'jisc62201969ro':
13492 case 'jp':
13493 return 'JIS_C6220-1969-ro';
13495 case 'csiso42jisc62261978':
13496 case 'isoir42':
13497 case 'jisc62261978':
13498 return 'JIS_C6226-1978';
13500 case 'csiso87jisx208':
13501 case 'isoir87':
13502 case 'jisc62261983':
13503 case 'jisx2081983':
13504 case 'x208':
13505 return 'JIS_C6226-1983';
13507 case 'csiso91jisc62291984a':
13508 case 'isoir91':
13509 case 'jisc62291984a':
13510 case 'jpocra':
13511 return 'JIS_C6229-1984-a';
13513 case 'csiso92jisc62991984b':
13514 case 'iso646jpocrb':
13515 case 'isoir92':
13516 case 'jisc62291984b':
13517 case 'jpocrb':
13518 return 'JIS_C6229-1984-b';
13520 case 'csiso93jis62291984badd':
13521 case 'isoir93':
13522 case 'jisc62291984badd':
13523 case 'jpocrbadd':
13524 return 'JIS_C6229-1984-b-add';
13526 case 'csiso94jis62291984hand':
13527 case 'isoir94':
13528 case 'jisc62291984hand':
13529 case 'jpocrhand':
13530 return 'JIS_C6229-1984-hand';
13532 case 'csiso95jis62291984handadd':
13533 case 'isoir95':
13534 case 'jisc62291984handadd':
13535 case 'jpocrhandadd':
13536 return 'JIS_C6229-1984-hand-add';
13538 case 'csiso96jisc62291984kana':
13539 case 'isoir96':
13540 case 'jisc62291984kana':
13541 return 'JIS_C6229-1984-kana';
13543 case 'csjisencoding':
13544 case 'jisencoding':
13545 return 'JIS_Encoding';
13547 case 'cshalfwidthkatakana':
13548 case 'jisx201':
13549 case 'x201':
13550 return 'JIS_X0201';
13552 case 'csiso159jisx2121990':
13553 case 'isoir159':
13554 case 'jisx2121990':
13555 case 'x212':
13556 return 'JIS_X0212-1990';
13558 case 'csiso141jusib1002':
13559 case 'iso646yu':
13560 case 'isoir141':
13561 case 'js':
13562 case 'jusib1002':
13563 case 'yu':
13564 return 'JUS_I.B1.002';
13566 case 'csiso147macedonian':
13567 case 'isoir147':
13568 case 'jusib1003mac':
13569 case 'macedonian':
13570 return 'JUS_I.B1.003-mac';
13572 case 'csiso146serbian':
13573 case 'isoir146':
13574 case 'jusib1003serb':
13575 case 'serbian':
13576 return 'JUS_I.B1.003-serb';
13578 case 'koi7switched':
13579 return 'KOI7-switched';
13581 case 'cskoi8r':
13582 case 'koi8r':
13583 return 'KOI8-R';
13585 case 'koi8u':
13586 return 'KOI8-U';
13588 case 'csksc5636':
13589 case 'iso646kr':
13590 case 'ksc5636':
13591 return 'KSC5636';
13593 case 'cskz1048':
13594 case 'kz1048':
13595 case 'rk1048':
13596 case 'strk10482002':
13597 return 'KZ-1048';
13599 case 'csiso19latingreek':
13600 case 'isoir19':
13601 case 'latingreek':
13602 return 'latin-greek';
13604 case 'csiso27latingreek1':
13605 case 'isoir27':
13606 case 'latingreek1':
13607 return 'Latin-greek-1';
13609 case 'csiso158lap':
13610 case 'isoir158':
13611 case 'lap':
13612 case 'latinlap':
13613 return 'latin-lap';
13615 case 'csmacintosh':
13616 case 'mac':
13617 case 'macintosh':
13618 return 'macintosh';
13620 case 'csmicrosoftpublishing':
13621 case 'microsoftpublishing':
13622 return 'Microsoft-Publishing';
13624 case 'csmnem':
13625 case 'mnem':
13626 return 'MNEM';
13628 case 'csmnemonic':
13629 case 'mnemonic':
13630 return 'MNEMONIC';
13632 case 'csiso86hungarian':
13633 case 'hu':
13634 case 'iso646hu':
13635 case 'isoir86':
13636 case 'msz77953':
13637 return 'MSZ_7795.3';
13639 case 'csnatsdano':
13640 case 'isoir91':
13641 case 'natsdano':
13642 return 'NATS-DANO';
13644 case 'csnatsdanoadd':
13645 case 'isoir92':
13646 case 'natsdanoadd':
13647 return 'NATS-DANO-ADD';
13649 case 'csnatssefi':
13650 case 'isoir81':
13651 case 'natssefi':
13652 return 'NATS-SEFI';
13654 case 'csnatssefiadd':
13655 case 'isoir82':
13656 case 'natssefiadd':
13657 return 'NATS-SEFI-ADD';
13659 case 'csiso151cuba':
13660 case 'cuba':
13661 case 'iso646cu':
13662 case 'isoir151':
13663 case 'ncnc1081':
13664 return 'NC_NC00-10:81';
13666 case 'csiso69french':
13667 case 'fr':
13668 case 'iso646fr':
13669 case 'isoir69':
13670 case 'nfz62010':
13671 return 'NF_Z_62-010';
13673 case 'csiso25french':
13674 case 'iso646fr1':
13675 case 'isoir25':
13676 case 'nfz620101973':
13677 return 'NF_Z_62-010_(1973)';
13679 case 'csiso60danishnorwegian':
13680 case 'csiso60norwegian1':
13681 case 'iso646no':
13682 case 'isoir60':
13683 case 'no':
13684 case 'ns45511':
13685 return 'NS_4551-1';
13687 case 'csiso61norwegian2':
13688 case 'iso646no2':
13689 case 'isoir61':
13690 case 'no2':
13691 case 'ns45512':
13692 return 'NS_4551-2';
13694 case 'osdebcdicdf3irv':
13695 return 'OSD_EBCDIC_DF03_IRV';
13697 case 'osdebcdicdf41':
13698 return 'OSD_EBCDIC_DF04_1';
13700 case 'osdebcdicdf415':
13701 return 'OSD_EBCDIC_DF04_15';
13703 case 'cspc8danishnorwegian':
13704 case 'pc8danishnorwegian':
13705 return 'PC8-Danish-Norwegian';
13707 case 'cspc8turkish':
13708 case 'pc8turkish':
13709 return 'PC8-Turkish';
13711 case 'csiso16portuguese':
13712 case 'iso646pt':
13713 case 'isoir16':
13714 case 'pt':
13715 return 'PT';
13717 case 'csiso84portuguese2':
13718 case 'iso646pt2':
13719 case 'isoir84':
13720 case 'pt2':
13721 return 'PT2';
13723 case 'cp154':
13724 case 'csptcp154':
13725 case 'cyrillicasian':
13726 case 'pt154':
13727 case 'ptcp154':
13728 return 'PTCP154';
13730 case 'scsu':
13731 return 'SCSU';
13733 case 'csiso10swedish':
13734 case 'fi':
13735 case 'iso646fi':
13736 case 'iso646se':
13737 case 'isoir10':
13738 case 'se':
13739 case 'sen850200b':
13740 return 'SEN_850200_B';
13742 case 'csiso11swedishfornames':
13743 case 'iso646se2':
13744 case 'isoir11':
13745 case 'se2':
13746 case 'sen850200c':
13747 return 'SEN_850200_C';
13749 case 'csiso102t617bit':
13750 case 'isoir102':
13751 case 't617bit':
13752 return 'T.61-7bit';
13754 case 'csiso103t618bit':
13755 case 'isoir103':
13756 case 't61':
13757 case 't618bit':
13758 return 'T.61-8bit';
13760 case 'csiso128t101g2':
13761 case 'isoir128':
13762 case 't101g2':
13763 return 'T.101-G2';
13765 case 'cstscii':
13766 case 'tscii':
13767 return 'TSCII';
13769 case 'csunicode11':
13770 case 'unicode11':
13771 return 'UNICODE-1-1';
13773 case 'csunicode11utf7':
13774 case 'unicode11utf7':
13775 return 'UNICODE-1-1-UTF-7';
13777 case 'csunknown8bit':
13778 case 'unknown8bit':
13779 return 'UNKNOWN-8BIT';
13781 case 'ansix341968':
13782 case 'ansix341986':
13783 case 'ascii':
13784 case 'cp367':
13785 case 'csascii':
13786 case 'ibm367':
13787 case 'iso646irv1991':
13788 case 'iso646us':
13789 case 'isoir6':
13790 case 'us':
13791 case 'usascii':
13792 return 'US-ASCII';
13794 case 'csusdk':
13795 case 'usdk':
13796 return 'us-dk';
13798 case 'utf7':
13799 return 'UTF-7';
13801 case 'utf8':
13802 return 'UTF-8';
13804 case 'utf16':
13805 return 'UTF-16';
13807 case 'utf16be':
13808 return 'UTF-16BE';
13810 case 'utf16le':
13811 return 'UTF-16LE';
13813 case 'utf32':
13814 return 'UTF-32';
13816 case 'utf32be':
13817 return 'UTF-32BE';
13819 case 'utf32le':
13820 return 'UTF-32LE';
13822 case 'csventurainternational':
13823 case 'venturainternational':
13824 return 'Ventura-International';
13826 case 'csventuramath':
13827 case 'venturamath':
13828 return 'Ventura-Math';
13830 case 'csventuraus':
13831 case 'venturaus':
13832 return 'Ventura-US';
13834 case 'csiso70videotexsupp1':
13835 case 'isoir70':
13836 case 'videotexsuppl':
13837 return 'videotex-suppl';
13839 case 'csviqr':
13840 case 'viqr':
13841 return 'VIQR';
13843 case 'csviscii':
13844 case 'viscii':
13845 return 'VISCII';
13847 case 'csshiftjis':
13848 case 'cswindows31j':
13849 case 'mskanji':
13850 case 'shiftjis':
13851 case 'windows31j':
13852 return 'Windows-31J';
13854 case 'iso885911':
13855 case 'tis620':
13856 return 'windows-874';
13858 case 'cseuckr':
13859 case 'csksc56011987':
13860 case 'euckr':
13861 case 'isoir149':
13862 case 'korean':
13863 case 'ksc5601':
13864 case 'ksc56011987':
13865 case 'ksc56011989':
13866 case 'windows949':
13867 return 'windows-949';
13869 case 'windows1250':
13870 return 'windows-1250';
13872 case 'windows1251':
13873 return 'windows-1251';
13875 case 'cp819':
13876 case 'csisolatin1':
13877 case 'ibm819':
13878 case 'iso88591':
13879 case 'iso885911987':
13880 case 'isoir100':
13881 case 'l1':
13882 case 'latin1':
13883 case 'windows1252':
13884 return 'windows-1252';
13886 case 'windows1253':
13887 return 'windows-1253';
13889 case 'csisolatin5':
13890 case 'iso88599':
13891 case 'iso885991989':
13892 case 'isoir148':
13893 case 'l5':
13894 case 'latin5':
13895 case 'windows1254':
13896 return 'windows-1254';
13898 case 'windows1255':
13899 return 'windows-1255';
13901 case 'windows1256':
13902 return 'windows-1256';
13904 case 'windows1257':
13905 return 'windows-1257';
13907 case 'windows1258':
13908 return 'windows-1258';
13910 default:
13911 return $charset;
13915 public static function get_curl_version()
13917 if (is_array($curl = curl_version()))
13919 $curl = $curl['version'];
13921 elseif (substr($curl, 0, 5) === 'curl/')
13923 $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
13925 elseif (substr($curl, 0, 8) === 'libcurl/')
13927 $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
13929 else
13931 $curl = 0;
13933 return $curl;
13937 * Strip HTML comments
13939 * @param string $data Data to strip comments from
13940 * @return string Comment stripped string
13942 public static function strip_comments($data)
13944 $output = '';
13945 while (($start = strpos($data, '<!--')) !== false)
13947 $output .= substr($data, 0, $start);
13948 if (($end = strpos($data, '-->', $start)) !== false)
13950 $data = substr_replace($data, '', 0, $end + 3);
13952 else
13954 $data = '';
13957 return $output . $data;
13960 public static function parse_date($dt)
13962 $parser = SimplePie_Parse_Date::get();
13963 return $parser->parse($dt);
13967 * Decode HTML entities
13969 * @deprecated Use DOMDocument instead
13970 * @param string $data Input data
13971 * @return string Output data
13973 public static function entities_decode($data)
13975 $decoder = new SimplePie_Decode_HTML_Entities($data);
13976 return $decoder->parse();
13980 * Remove RFC822 comments
13982 * @param string $data Data to strip comments from
13983 * @return string Comment stripped string
13985 public static function uncomment_rfc822($string)
13987 $string = (string) $string;
13988 $position = 0;
13989 $length = strlen($string);
13990 $depth = 0;
13992 $output = '';
13994 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
13996 $output .= substr($string, $position, $pos - $position);
13997 $position = $pos + 1;
13998 if ($string[$pos - 1] !== '\\')
14000 $depth++;
14001 while ($depth && $position < $length)
14003 $position += strcspn($string, '()', $position);
14004 if ($string[$position - 1] === '\\')
14006 $position++;
14007 continue;
14009 elseif (isset($string[$position]))
14011 switch ($string[$position])
14013 case '(':
14014 $depth++;
14015 break;
14017 case ')':
14018 $depth--;
14019 break;
14021 $position++;
14023 else
14025 break;
14029 else
14031 $output .= '(';
14034 $output .= substr($string, $position);
14036 return $output;
14039 public static function parse_mime($mime)
14041 if (($pos = strpos($mime, ';')) === false)
14043 return trim($mime);
14045 else
14047 return trim(substr($mime, 0, $pos));
14051 public static function atom_03_construct_type($attribs)
14053 if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
14055 $mode = SIMPLEPIE_CONSTRUCT_BASE64;
14057 else
14059 $mode = SIMPLEPIE_CONSTRUCT_NONE;
14061 if (isset($attribs['']['type']))
14063 switch (strtolower(trim($attribs['']['type'])))
14065 case 'text':
14066 case 'text/plain':
14067 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
14069 case 'html':
14070 case 'text/html':
14071 return SIMPLEPIE_CONSTRUCT_HTML | $mode;
14073 case 'xhtml':
14074 case 'application/xhtml+xml':
14075 return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
14077 default:
14078 return SIMPLEPIE_CONSTRUCT_NONE | $mode;
14081 else
14083 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
14087 public static function atom_10_construct_type($attribs)
14089 if (isset($attribs['']['type']))
14091 switch (strtolower(trim($attribs['']['type'])))
14093 case 'text':
14094 return SIMPLEPIE_CONSTRUCT_TEXT;
14096 case 'html':
14097 return SIMPLEPIE_CONSTRUCT_HTML;
14099 case 'xhtml':
14100 return SIMPLEPIE_CONSTRUCT_XHTML;
14102 default:
14103 return SIMPLEPIE_CONSTRUCT_NONE;
14106 return SIMPLEPIE_CONSTRUCT_TEXT;
14109 public static function atom_10_content_construct_type($attribs)
14111 if (isset($attribs['']['type']))
14113 $type = strtolower(trim($attribs['']['type']));
14114 switch ($type)
14116 case 'text':
14117 return SIMPLEPIE_CONSTRUCT_TEXT;
14119 case 'html':
14120 return SIMPLEPIE_CONSTRUCT_HTML;
14122 case 'xhtml':
14123 return SIMPLEPIE_CONSTRUCT_XHTML;
14125 if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
14127 return SIMPLEPIE_CONSTRUCT_NONE;
14129 else
14131 return SIMPLEPIE_CONSTRUCT_BASE64;
14134 else
14136 return SIMPLEPIE_CONSTRUCT_TEXT;
14140 public static function is_isegment_nz_nc($string)
14142 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);
14145 public static function space_seperated_tokens($string)
14147 $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
14148 $string_length = strlen($string);
14150 $position = strspn($string, $space_characters);
14151 $tokens = array();
14153 while ($position < $string_length)
14155 $len = strcspn($string, $space_characters, $position);
14156 $tokens[] = substr($string, $position, $len);
14157 $position += $len;
14158 $position += strspn($string, $space_characters, $position);
14161 return $tokens;
14165 * Converts a unicode codepoint to a UTF-8 character
14167 * @static
14168 * @param int $codepoint Unicode codepoint
14169 * @return string UTF-8 character
14171 public static function codepoint_to_utf8($codepoint)
14173 $codepoint = (int) $codepoint;
14174 if ($codepoint < 0)
14176 return false;
14178 else if ($codepoint <= 0x7f)
14180 return chr($codepoint);
14182 else if ($codepoint <= 0x7ff)
14184 return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
14186 else if ($codepoint <= 0xffff)
14188 return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
14190 else if ($codepoint <= 0x10ffff)
14192 return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
14194 else
14196 // U+FFFD REPLACEMENT CHARACTER
14197 return "\xEF\xBF\xBD";
14202 * Similar to parse_str()
14204 * Returns an associative array of name/value pairs, where the value is an
14205 * array of values that have used the same name
14207 * @static
14208 * @param string $str The input string.
14209 * @return array
14211 public static function parse_str($str)
14213 $return = array();
14214 $str = explode('&', $str);
14216 foreach ($str as $section)
14218 if (strpos($section, '=') !== false)
14220 list($name, $value) = explode('=', $section, 2);
14221 $return[urldecode($name)][] = urldecode($value);
14223 else
14225 $return[urldecode($section)][] = null;
14229 return $return;
14233 * Detect XML encoding, as per XML 1.0 Appendix F.1
14235 * @todo Add support for EBCDIC
14236 * @param string $data XML data
14237 * @param SimplePie_Registry $registry Class registry
14238 * @return array Possible encodings
14240 public static function xml_encoding($data, $registry)
14242 // UTF-32 Big Endian BOM
14243 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
14245 $encoding[] = 'UTF-32BE';
14247 // UTF-32 Little Endian BOM
14248 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
14250 $encoding[] = 'UTF-32LE';
14252 // UTF-16 Big Endian BOM
14253 elseif (substr($data, 0, 2) === "\xFE\xFF")
14255 $encoding[] = 'UTF-16BE';
14257 // UTF-16 Little Endian BOM
14258 elseif (substr($data, 0, 2) === "\xFF\xFE")
14260 $encoding[] = 'UTF-16LE';
14262 // UTF-8 BOM
14263 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
14265 $encoding[] = 'UTF-8';
14267 // UTF-32 Big Endian Without BOM
14268 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")
14270 if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
14272 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
14273 if ($parser->parse())
14275 $encoding[] = $parser->encoding;
14278 $encoding[] = 'UTF-32BE';
14280 // UTF-32 Little Endian Without BOM
14281 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")
14283 if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
14285 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
14286 if ($parser->parse())
14288 $encoding[] = $parser->encoding;
14291 $encoding[] = 'UTF-32LE';
14293 // UTF-16 Big Endian Without BOM
14294 elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
14296 if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
14298 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
14299 if ($parser->parse())
14301 $encoding[] = $parser->encoding;
14304 $encoding[] = 'UTF-16BE';
14306 // UTF-16 Little Endian Without BOM
14307 elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
14309 if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
14311 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
14312 if ($parser->parse())
14314 $encoding[] = $parser->encoding;
14317 $encoding[] = 'UTF-16LE';
14319 // US-ASCII (or superset)
14320 elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
14322 if ($pos = strpos($data, "\x3F\x3E"))
14324 $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
14325 if ($parser->parse())
14327 $encoding[] = $parser->encoding;
14330 $encoding[] = 'UTF-8';
14332 // Fallback to UTF-8
14333 else
14335 $encoding[] = 'UTF-8';
14337 return $encoding;
14340 public static function output_javascript()
14342 if (function_exists('ob_gzhandler'))
14344 ob_start('ob_gzhandler');
14346 header('Content-type: text/javascript; charset: UTF-8');
14347 header('Cache-Control: must-revalidate');
14348 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
14350 function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
14351 if (placeholder != '') {
14352 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>');
14354 else {
14355 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>');
14359 function embed_flash(bgcolor, width, height, link, loop, type) {
14360 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>');
14363 function embed_flv(width, height, link, placeholder, loop, player) {
14364 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>');
14367 function embed_wmedia(width, height, link) {
14368 document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
14370 <?php
14374 * Get the SimplePie build timestamp
14376 * Uses the git index if it exists, otherwise uses the modification time
14377 * of the newest file.
14379 public static function get_build()
14381 $root = dirname(dirname(__FILE__));
14382 if (file_exists($root . '/.git/index'))
14384 return filemtime($root . '/.git/index');
14386 elseif (file_exists($root . '/SimplePie'))
14388 $time = 0;
14389 foreach (glob($root . '/SimplePie/*.php') as $file)
14391 if (($mtime = filemtime($file)) > $time)
14393 $time = $mtime;
14396 return $time;
14398 elseif (file_exists(dirname(__FILE__) . '/Core.php'))
14400 return filemtime(dirname(__FILE__) . '/Core.php');
14402 else
14404 return filemtime(__FILE__);
14409 * Format debugging information
14411 public static function debug(&$sp)
14413 $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
14414 $info .= 'PHP ' . PHP_VERSION . "\n";
14415 if ($sp->error() !== null)
14417 $info .= 'Error occurred: ' . $sp->error() . "\n";
14419 else
14421 $info .= "No error found.\n";
14423 $info .= "Extensions:\n";
14424 $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
14425 foreach ($extensions as $ext)
14427 if (extension_loaded($ext))
14429 $info .= " $ext loaded\n";
14430 switch ($ext)
14432 case 'pcre':
14433 $info .= ' Version ' . PCRE_VERSION . "\n";
14434 break;
14435 case 'curl':
14436 $version = curl_version();
14437 $info .= ' Version ' . $version['version'] . "\n";
14438 break;
14439 case 'mbstring':
14440 $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
14441 break;
14442 case 'iconv':
14443 $info .= ' Version ' . ICONV_VERSION . "\n";
14444 break;
14445 case 'xml':
14446 $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
14447 break;
14450 else
14452 $info .= " $ext not loaded\n";
14455 return $info;
14458 public static function silence_errors($num, $str)
14460 // No-op
14465 * Class to validate and to work with IPv6 addresses.
14467 * @package SimplePie
14468 * @subpackage HTTP
14469 * @copyright 2003-2005 The PHP Group
14470 * @license http://www.opensource.org/licenses/bsd-license.php
14471 * @link http://pear.php.net/package/Net_IPv6
14472 * @author Alexander Merz <alexander.merz@web.de>
14473 * @author elfrink at introweb dot nl
14474 * @author Josh Peck <jmp at joshpeck dot org>
14475 * @author Geoffrey Sneddon <geoffers@gmail.com>
14477 class SimplePie_Net_IPv6
14480 * Uncompresses an IPv6 address
14482 * RFC 4291 allows you to compress concecutive zero pieces in an address to
14483 * '::'. This method expects a valid IPv6 address and expands the '::' to
14484 * the required number of zero pieces.
14486 * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
14487 * ::1 -> 0:0:0:0:0:0:0:1
14489 * @author Alexander Merz <alexander.merz@web.de>
14490 * @author elfrink at introweb dot nl
14491 * @author Josh Peck <jmp at joshpeck dot org>
14492 * @copyright 2003-2005 The PHP Group
14493 * @license http://www.opensource.org/licenses/bsd-license.php
14494 * @param string $ip An IPv6 address
14495 * @return string The uncompressed IPv6 address
14497 public static function uncompress($ip)
14499 $c1 = -1;
14500 $c2 = -1;
14501 if (substr_count($ip, '::') === 1)
14503 list($ip1, $ip2) = explode('::', $ip);
14504 if ($ip1 === '')
14506 $c1 = -1;
14508 else
14510 $c1 = substr_count($ip1, ':');
14512 if ($ip2 === '')
14514 $c2 = -1;
14516 else
14518 $c2 = substr_count($ip2, ':');
14520 if (strpos($ip2, '.') !== false)
14522 $c2++;
14524 // ::
14525 if ($c1 === -1 && $c2 === -1)
14527 $ip = '0:0:0:0:0:0:0:0';
14529 // ::xxx
14530 else if ($c1 === -1)
14532 $fill = str_repeat('0:', 7 - $c2);
14533 $ip = str_replace('::', $fill, $ip);
14535 // xxx::
14536 else if ($c2 === -1)
14538 $fill = str_repeat(':0', 7 - $c1);
14539 $ip = str_replace('::', $fill, $ip);
14541 // xxx::xxx
14542 else
14544 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
14545 $ip = str_replace('::', $fill, $ip);
14548 return $ip;
14552 * Compresses an IPv6 address
14554 * RFC 4291 allows you to compress concecutive zero pieces in an address to
14555 * '::'. This method expects a valid IPv6 address and compresses consecutive
14556 * zero pieces to '::'.
14558 * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
14559 * 0:0:0:0:0:0:0:1 -> ::1
14561 * @see uncompress()
14562 * @param string $ip An IPv6 address
14563 * @return string The compressed IPv6 address
14565 public static function compress($ip)
14567 // Prepare the IP to be compressed
14568 $ip = self::uncompress($ip);
14569 $ip_parts = self::split_v6_v4($ip);
14571 // Replace all leading zeros
14572 $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
14574 // Find bunches of zeros
14575 if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
14577 $max = 0;
14578 $pos = null;
14579 foreach ($matches[0] as $match)
14581 if (strlen($match[0]) > $max)
14583 $max = strlen($match[0]);
14584 $pos = $match[1];
14588 $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
14591 if ($ip_parts[1] !== '')
14593 return implode(':', $ip_parts);
14595 else
14597 return $ip_parts[0];
14602 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
14604 * RFC 4291 allows you to represent the last two parts of an IPv6 address
14605 * using the standard IPv4 representation
14607 * Example: 0:0:0:0:0:0:13.1.68.3
14608 * 0:0:0:0:0:FFFF:129.144.52.38
14610 * @param string $ip An IPv6 address
14611 * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
14613 private static function split_v6_v4($ip)
14615 if (strpos($ip, '.') !== false)
14617 $pos = strrpos($ip, ':');
14618 $ipv6_part = substr($ip, 0, $pos);
14619 $ipv4_part = substr($ip, $pos + 1);
14620 return array($ipv6_part, $ipv4_part);
14622 else
14624 return array($ip, '');
14629 * Checks an IPv6 address
14631 * Checks if the given IP is a valid IPv6 address
14633 * @param string $ip An IPv6 address
14634 * @return bool true if $ip is a valid IPv6 address
14636 public static function check_ipv6($ip)
14638 $ip = self::uncompress($ip);
14639 list($ipv6, $ipv4) = self::split_v6_v4($ip);
14640 $ipv6 = explode(':', $ipv6);
14641 $ipv4 = explode('.', $ipv4);
14642 if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
14644 foreach ($ipv6 as $ipv6_part)
14646 // The section can't be empty
14647 if ($ipv6_part === '')
14648 return false;
14650 // Nor can it be over four characters
14651 if (strlen($ipv6_part) > 4)
14652 return false;
14654 // Remove leading zeros (this is safe because of the above)
14655 $ipv6_part = ltrim($ipv6_part, '0');
14656 if ($ipv6_part === '')
14657 $ipv6_part = '0';
14659 // Check the value is valid
14660 $value = hexdec($ipv6_part);
14661 if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
14662 return false;
14664 if (count($ipv4) === 4)
14666 foreach ($ipv4 as $ipv4_part)
14668 $value = (int) $ipv4_part;
14669 if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
14670 return false;
14673 return true;
14675 else
14677 return false;
14682 * Checks if the given IP is a valid IPv6 address
14684 * @codeCoverageIgnore
14685 * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
14686 * @see check_ipv6
14687 * @param string $ip An IPv6 address
14688 * @return bool true if $ip is a valid IPv6 address
14690 public static function checkIPv6($ip)
14692 return self::check_ipv6($ip);
14697 * Date Parser
14699 * @package SimplePie
14700 * @subpackage Parsing
14702 class SimplePie_Parse_Date
14705 * Input data
14707 * @access protected
14708 * @var string
14710 var $date;
14713 * List of days, calendar day name => ordinal day number in the week
14715 * @access protected
14716 * @var array
14718 var $day = array(
14719 // English
14720 'mon' => 1,
14721 'monday' => 1,
14722 'tue' => 2,
14723 'tuesday' => 2,
14724 'wed' => 3,
14725 'wednesday' => 3,
14726 'thu' => 4,
14727 'thursday' => 4,
14728 'fri' => 5,
14729 'friday' => 5,
14730 'sat' => 6,
14731 'saturday' => 6,
14732 'sun' => 7,
14733 'sunday' => 7,
14734 // Dutch
14735 'maandag' => 1,
14736 'dinsdag' => 2,
14737 'woensdag' => 3,
14738 'donderdag' => 4,
14739 'vrijdag' => 5,
14740 'zaterdag' => 6,
14741 'zondag' => 7,
14742 // French
14743 'lundi' => 1,
14744 'mardi' => 2,
14745 'mercredi' => 3,
14746 'jeudi' => 4,
14747 'vendredi' => 5,
14748 'samedi' => 6,
14749 'dimanche' => 7,
14750 // German
14751 'montag' => 1,
14752 'dienstag' => 2,
14753 'mittwoch' => 3,
14754 'donnerstag' => 4,
14755 'freitag' => 5,
14756 'samstag' => 6,
14757 'sonnabend' => 6,
14758 'sonntag' => 7,
14759 // Italian
14760 'lunedì' => 1,
14761 'martedì' => 2,
14762 'mercoledì' => 3,
14763 'giovedì' => 4,
14764 'venerdì' => 5,
14765 'sabato' => 6,
14766 'domenica' => 7,
14767 // Spanish
14768 'lunes' => 1,
14769 'martes' => 2,
14770 'miércoles' => 3,
14771 'jueves' => 4,
14772 'viernes' => 5,
14773 'sábado' => 6,
14774 'domingo' => 7,
14775 // Finnish
14776 'maanantai' => 1,
14777 'tiistai' => 2,
14778 'keskiviikko' => 3,
14779 'torstai' => 4,
14780 'perjantai' => 5,
14781 'lauantai' => 6,
14782 'sunnuntai' => 7,
14783 // Hungarian
14784 'hétfő' => 1,
14785 'kedd' => 2,
14786 'szerda' => 3,
14787 'csütörtok' => 4,
14788 'péntek' => 5,
14789 'szombat' => 6,
14790 'vasárnap' => 7,
14791 // Greek
14792 'Δευ' => 1,
14793 'Τρι' => 2,
14794 'Τετ' => 3,
14795 'Πεμ' => 4,
14796 'Παρ' => 5,
14797 'Σαβ' => 6,
14798 'Κυρ' => 7,
14802 * List of months, calendar month name => calendar month number
14804 * @access protected
14805 * @var array
14807 var $month = array(
14808 // English
14809 'jan' => 1,
14810 'january' => 1,
14811 'feb' => 2,
14812 'february' => 2,
14813 'mar' => 3,
14814 'march' => 3,
14815 'apr' => 4,
14816 'april' => 4,
14817 'may' => 5,
14818 // No long form of May
14819 'jun' => 6,
14820 'june' => 6,
14821 'jul' => 7,
14822 'july' => 7,
14823 'aug' => 8,
14824 'august' => 8,
14825 'sep' => 9,
14826 'september' => 8,
14827 'oct' => 10,
14828 'october' => 10,
14829 'nov' => 11,
14830 'november' => 11,
14831 'dec' => 12,
14832 'december' => 12,
14833 // Dutch
14834 'januari' => 1,
14835 'februari' => 2,
14836 'maart' => 3,
14837 'april' => 4,
14838 'mei' => 5,
14839 'juni' => 6,
14840 'juli' => 7,
14841 'augustus' => 8,
14842 'september' => 9,
14843 'oktober' => 10,
14844 'november' => 11,
14845 'december' => 12,
14846 // French
14847 'janvier' => 1,
14848 'février' => 2,
14849 'mars' => 3,
14850 'avril' => 4,
14851 'mai' => 5,
14852 'juin' => 6,
14853 'juillet' => 7,
14854 'août' => 8,
14855 'septembre' => 9,
14856 'octobre' => 10,
14857 'novembre' => 11,
14858 'décembre' => 12,
14859 // German
14860 'januar' => 1,
14861 'februar' => 2,
14862 'märz' => 3,
14863 'april' => 4,
14864 'mai' => 5,
14865 'juni' => 6,
14866 'juli' => 7,
14867 'august' => 8,
14868 'september' => 9,
14869 'oktober' => 10,
14870 'november' => 11,
14871 'dezember' => 12,
14872 // Italian
14873 'gennaio' => 1,
14874 'febbraio' => 2,
14875 'marzo' => 3,
14876 'aprile' => 4,
14877 'maggio' => 5,
14878 'giugno' => 6,
14879 'luglio' => 7,
14880 'agosto' => 8,
14881 'settembre' => 9,
14882 'ottobre' => 10,
14883 'novembre' => 11,
14884 'dicembre' => 12,
14885 // Spanish
14886 'enero' => 1,
14887 'febrero' => 2,
14888 'marzo' => 3,
14889 'abril' => 4,
14890 'mayo' => 5,
14891 'junio' => 6,
14892 'julio' => 7,
14893 'agosto' => 8,
14894 'septiembre' => 9,
14895 'setiembre' => 9,
14896 'octubre' => 10,
14897 'noviembre' => 11,
14898 'diciembre' => 12,
14899 // Finnish
14900 'tammikuu' => 1,
14901 'helmikuu' => 2,
14902 'maaliskuu' => 3,
14903 'huhtikuu' => 4,
14904 'toukokuu' => 5,
14905 'kesäkuu' => 6,
14906 'heinäkuu' => 7,
14907 'elokuu' => 8,
14908 'suuskuu' => 9,
14909 'lokakuu' => 10,
14910 'marras' => 11,
14911 'joulukuu' => 12,
14912 // Hungarian
14913 'január' => 1,
14914 'február' => 2,
14915 'március' => 3,
14916 'április' => 4,
14917 'május' => 5,
14918 'június' => 6,
14919 'július' => 7,
14920 'augusztus' => 8,
14921 'szeptember' => 9,
14922 'október' => 10,
14923 'november' => 11,
14924 'december' => 12,
14925 // Greek
14926 'Ιαν' => 1,
14927 'Φεβ' => 2,
14928 'Μάώ' => 3,
14929 'Μαώ' => 3,
14930 'Απρ' => 4,
14931 'Μάι' => 5,
14932 'Μαϊ' => 5,
14933 'Μαι' => 5,
14934 'Ιούν' => 6,
14935 'Ιον' => 6,
14936 'Ιούλ' => 7,
14937 'Ιολ' => 7,
14938 'Αύγ' => 8,
14939 'Αυγ' => 8,
14940 'Σεπ' => 9,
14941 'Οκτ' => 10,
14942 'Νοέ' => 11,
14943 'Δεκ' => 12,
14947 * List of timezones, abbreviation => offset from UTC
14949 * @access protected
14950 * @var array
14952 var $timezone = array(
14953 'ACDT' => 37800,
14954 'ACIT' => 28800,
14955 'ACST' => 34200,
14956 'ACT' => -18000,
14957 'ACWDT' => 35100,
14958 'ACWST' => 31500,
14959 'AEDT' => 39600,
14960 'AEST' => 36000,
14961 'AFT' => 16200,
14962 'AKDT' => -28800,
14963 'AKST' => -32400,
14964 'AMDT' => 18000,
14965 'AMT' => -14400,
14966 'ANAST' => 46800,
14967 'ANAT' => 43200,
14968 'ART' => -10800,
14969 'AZOST' => -3600,
14970 'AZST' => 18000,
14971 'AZT' => 14400,
14972 'BIOT' => 21600,
14973 'BIT' => -43200,
14974 'BOT' => -14400,
14975 'BRST' => -7200,
14976 'BRT' => -10800,
14977 'BST' => 3600,
14978 'BTT' => 21600,
14979 'CAST' => 18000,
14980 'CAT' => 7200,
14981 'CCT' => 23400,
14982 'CDT' => -18000,
14983 'CEDT' => 7200,
14984 'CET' => 3600,
14985 'CGST' => -7200,
14986 'CGT' => -10800,
14987 'CHADT' => 49500,
14988 'CHAST' => 45900,
14989 'CIST' => -28800,
14990 'CKT' => -36000,
14991 'CLDT' => -10800,
14992 'CLST' => -14400,
14993 'COT' => -18000,
14994 'CST' => -21600,
14995 'CVT' => -3600,
14996 'CXT' => 25200,
14997 'DAVT' => 25200,
14998 'DTAT' => 36000,
14999 'EADT' => -18000,
15000 'EAST' => -21600,
15001 'EAT' => 10800,
15002 'ECT' => -18000,
15003 'EDT' => -14400,
15004 'EEST' => 10800,
15005 'EET' => 7200,
15006 'EGT' => -3600,
15007 'EKST' => 21600,
15008 'EST' => -18000,
15009 'FJT' => 43200,
15010 'FKDT' => -10800,
15011 'FKST' => -14400,
15012 'FNT' => -7200,
15013 'GALT' => -21600,
15014 'GEDT' => 14400,
15015 'GEST' => 10800,
15016 'GFT' => -10800,
15017 'GILT' => 43200,
15018 'GIT' => -32400,
15019 'GST' => 14400,
15020 'GST' => -7200,
15021 'GYT' => -14400,
15022 'HAA' => -10800,
15023 'HAC' => -18000,
15024 'HADT' => -32400,
15025 'HAE' => -14400,
15026 'HAP' => -25200,
15027 'HAR' => -21600,
15028 'HAST' => -36000,
15029 'HAT' => -9000,
15030 'HAY' => -28800,
15031 'HKST' => 28800,
15032 'HMT' => 18000,
15033 'HNA' => -14400,
15034 'HNC' => -21600,
15035 'HNE' => -18000,
15036 'HNP' => -28800,
15037 'HNR' => -25200,
15038 'HNT' => -12600,
15039 'HNY' => -32400,
15040 'IRDT' => 16200,
15041 'IRKST' => 32400,
15042 'IRKT' => 28800,
15043 'IRST' => 12600,
15044 'JFDT' => -10800,
15045 'JFST' => -14400,
15046 'JST' => 32400,
15047 'KGST' => 21600,
15048 'KGT' => 18000,
15049 'KOST' => 39600,
15050 'KOVST' => 28800,
15051 'KOVT' => 25200,
15052 'KRAST' => 28800,
15053 'KRAT' => 25200,
15054 'KST' => 32400,
15055 'LHDT' => 39600,
15056 'LHST' => 37800,
15057 'LINT' => 50400,
15058 'LKT' => 21600,
15059 'MAGST' => 43200,
15060 'MAGT' => 39600,
15061 'MAWT' => 21600,
15062 'MDT' => -21600,
15063 'MESZ' => 7200,
15064 'MEZ' => 3600,
15065 'MHT' => 43200,
15066 'MIT' => -34200,
15067 'MNST' => 32400,
15068 'MSDT' => 14400,
15069 'MSST' => 10800,
15070 'MST' => -25200,
15071 'MUT' => 14400,
15072 'MVT' => 18000,
15073 'MYT' => 28800,
15074 'NCT' => 39600,
15075 'NDT' => -9000,
15076 'NFT' => 41400,
15077 'NMIT' => 36000,
15078 'NOVST' => 25200,
15079 'NOVT' => 21600,
15080 'NPT' => 20700,
15081 'NRT' => 43200,
15082 'NST' => -12600,
15083 'NUT' => -39600,
15084 'NZDT' => 46800,
15085 'NZST' => 43200,
15086 'OMSST' => 25200,
15087 'OMST' => 21600,
15088 'PDT' => -25200,
15089 'PET' => -18000,
15090 'PETST' => 46800,
15091 'PETT' => 43200,
15092 'PGT' => 36000,
15093 'PHOT' => 46800,
15094 'PHT' => 28800,
15095 'PKT' => 18000,
15096 'PMDT' => -7200,
15097 'PMST' => -10800,
15098 'PONT' => 39600,
15099 'PST' => -28800,
15100 'PWT' => 32400,
15101 'PYST' => -10800,
15102 'PYT' => -14400,
15103 'RET' => 14400,
15104 'ROTT' => -10800,
15105 'SAMST' => 18000,
15106 'SAMT' => 14400,
15107 'SAST' => 7200,
15108 'SBT' => 39600,
15109 'SCDT' => 46800,
15110 'SCST' => 43200,
15111 'SCT' => 14400,
15112 'SEST' => 3600,
15113 'SGT' => 28800,
15114 'SIT' => 28800,
15115 'SRT' => -10800,
15116 'SST' => -39600,
15117 'SYST' => 10800,
15118 'SYT' => 7200,
15119 'TFT' => 18000,
15120 'THAT' => -36000,
15121 'TJT' => 18000,
15122 'TKT' => -36000,
15123 'TMT' => 18000,
15124 'TOT' => 46800,
15125 'TPT' => 32400,
15126 'TRUT' => 36000,
15127 'TVT' => 43200,
15128 'TWT' => 28800,
15129 'UYST' => -7200,
15130 'UYT' => -10800,
15131 'UZT' => 18000,
15132 'VET' => -14400,
15133 'VLAST' => 39600,
15134 'VLAT' => 36000,
15135 'VOST' => 21600,
15136 'VUT' => 39600,
15137 'WAST' => 7200,
15138 'WAT' => 3600,
15139 'WDT' => 32400,
15140 'WEST' => 3600,
15141 'WFT' => 43200,
15142 'WIB' => 25200,
15143 'WIT' => 32400,
15144 'WITA' => 28800,
15145 'WKST' => 18000,
15146 'WST' => 28800,
15147 'YAKST' => 36000,
15148 'YAKT' => 32400,
15149 'YAPT' => 36000,
15150 'YEKST' => 21600,
15151 'YEKT' => 18000,
15155 * Cached PCRE for SimplePie_Parse_Date::$day
15157 * @access protected
15158 * @var string
15160 var $day_pcre;
15163 * Cached PCRE for SimplePie_Parse_Date::$month
15165 * @access protected
15166 * @var string
15168 var $month_pcre;
15171 * Array of user-added callback methods
15173 * @access private
15174 * @var array
15176 var $built_in = array();
15179 * Array of user-added callback methods
15181 * @access private
15182 * @var array
15184 var $user = array();
15187 * Create new SimplePie_Parse_Date object, and set self::day_pcre,
15188 * self::month_pcre, and self::built_in
15190 * @access private
15192 public function __construct()
15194 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
15195 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
15197 static $cache;
15198 if (!isset($cache[get_class($this)]))
15200 $all_methods = get_class_methods($this);
15202 foreach ($all_methods as $method)
15204 if (strtolower(substr($method, 0, 5)) === 'date_')
15206 $cache[get_class($this)][] = $method;
15211 foreach ($cache[get_class($this)] as $method)
15213 $this->built_in[] = $method;
15218 * Get the object
15220 * @access public
15222 public static function get()
15224 static $object;
15225 if (!$object)
15227 $object = new SimplePie_Parse_Date;
15229 return $object;
15233 * Parse a date
15235 * @final
15236 * @access public
15237 * @param string $date Date to parse
15238 * @return int Timestamp corresponding to date string, or false on failure
15240 public function parse($date)
15242 foreach ($this->user as $method)
15244 if (($returned = call_user_func($method, $date)) !== false)
15246 return $returned;
15250 foreach ($this->built_in as $method)
15252 if (($returned = call_user_func(array($this, $method), $date)) !== false)
15254 return $returned;
15258 return false;
15262 * Add a callback method to parse a date
15264 * @final
15265 * @access public
15266 * @param callback $callback
15268 public function add_callback($callback)
15270 if (is_callable($callback))
15272 $this->user[] = $callback;
15274 else
15276 trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
15281 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
15282 * well as allowing any of upper or lower case "T", horizontal tabs, or
15283 * spaces to be used as the time seperator (including more than one))
15285 * @access protected
15286 * @return int Timestamp
15288 public function date_w3cdtf($date)
15290 static $pcre;
15291 if (!$pcre)
15293 $year = '([0-9]{4})';
15294 $month = $day = $hour = $minute = $second = '([0-9]{2})';
15295 $decimal = '([0-9]*)';
15296 $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
15297 $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
15299 if (preg_match($pcre, $date, $match))
15302 Capturing subpatterns:
15303 1: Year
15304 2: Month
15305 3: Day
15306 4: Hour
15307 5: Minute
15308 6: Second
15309 7: Decimal fraction of a second
15310 8: Zulu
15311 9: Timezone ±
15312 10: Timezone hours
15313 11: Timezone minutes
15316 // Fill in empty matches
15317 for ($i = count($match); $i <= 3; $i++)
15319 $match[$i] = '1';
15322 for ($i = count($match); $i <= 7; $i++)
15324 $match[$i] = '0';
15327 // Numeric timezone
15328 if (isset($match[9]) && $match[9] !== '')
15330 $timezone = $match[10] * 3600;
15331 $timezone += $match[11] * 60;
15332 if ($match[9] === '-')
15334 $timezone = 0 - $timezone;
15337 else
15339 $timezone = 0;
15342 // Convert the number of seconds to an integer, taking decimals into account
15343 $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
15345 return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
15347 else
15349 return false;
15354 * Remove RFC822 comments
15356 * @access protected
15357 * @param string $data Data to strip comments from
15358 * @return string Comment stripped string
15360 public function remove_rfc2822_comments($string)
15362 $string = (string) $string;
15363 $position = 0;
15364 $length = strlen($string);
15365 $depth = 0;
15367 $output = '';
15369 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
15371 $output .= substr($string, $position, $pos - $position);
15372 $position = $pos + 1;
15373 if ($string[$pos - 1] !== '\\')
15375 $depth++;
15376 while ($depth && $position < $length)
15378 $position += strcspn($string, '()', $position);
15379 if ($string[$position - 1] === '\\')
15381 $position++;
15382 continue;
15384 elseif (isset($string[$position]))
15386 switch ($string[$position])
15388 case '(':
15389 $depth++;
15390 break;
15392 case ')':
15393 $depth--;
15394 break;
15396 $position++;
15398 else
15400 break;
15404 else
15406 $output .= '(';
15409 $output .= substr($string, $position);
15411 return $output;
15415 * Parse RFC2822's date format
15417 * @access protected
15418 * @return int Timestamp
15420 public function date_rfc2822($date)
15422 static $pcre;
15423 if (!$pcre)
15425 $wsp = '[\x09\x20]';
15426 $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
15427 $optional_fws = $fws . '?';
15428 $day_name = $this->day_pcre;
15429 $month = $this->month_pcre;
15430 $day = '([0-9]{1,2})';
15431 $hour = $minute = $second = '([0-9]{2})';
15432 $year = '([0-9]{2,4})';
15433 $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
15434 $character_zone = '([A-Z]{1,5})';
15435 $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
15436 $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';
15438 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
15441 Capturing subpatterns:
15442 1: Day name
15443 2: Day
15444 3: Month
15445 4: Year
15446 5: Hour
15447 6: Minute
15448 7: Second
15449 8: Timezone ±
15450 9: Timezone hours
15451 10: Timezone minutes
15452 11: Alphabetic timezone
15455 // Find the month number
15456 $month = $this->month[strtolower($match[3])];
15458 // Numeric timezone
15459 if ($match[8] !== '')
15461 $timezone = $match[9] * 3600;
15462 $timezone += $match[10] * 60;
15463 if ($match[8] === '-')
15465 $timezone = 0 - $timezone;
15468 // Character timezone
15469 elseif (isset($this->timezone[strtoupper($match[11])]))
15471 $timezone = $this->timezone[strtoupper($match[11])];
15473 // Assume everything else to be -0000
15474 else
15476 $timezone = 0;
15479 // Deal with 2/3 digit years
15480 if ($match[4] < 50)
15482 $match[4] += 2000;
15484 elseif ($match[4] < 1000)
15486 $match[4] += 1900;
15489 // Second is optional, if it is empty set it to zero
15490 if ($match[7] !== '')
15492 $second = $match[7];
15494 else
15496 $second = 0;
15499 return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
15501 else
15503 return false;
15508 * Parse RFC850's date format
15510 * @access protected
15511 * @return int Timestamp
15513 public function date_rfc850($date)
15515 static $pcre;
15516 if (!$pcre)
15518 $space = '[\x09\x20]+';
15519 $day_name = $this->day_pcre;
15520 $month = $this->month_pcre;
15521 $day = '([0-9]{1,2})';
15522 $year = $hour = $minute = $second = '([0-9]{2})';
15523 $zone = '([A-Z]{1,5})';
15524 $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
15526 if (preg_match($pcre, $date, $match))
15529 Capturing subpatterns:
15530 1: Day name
15531 2: Day
15532 3: Month
15533 4: Year
15534 5: Hour
15535 6: Minute
15536 7: Second
15537 8: Timezone
15540 // Month
15541 $month = $this->month[strtolower($match[3])];
15543 // Character timezone
15544 if (isset($this->timezone[strtoupper($match[8])]))
15546 $timezone = $this->timezone[strtoupper($match[8])];
15548 // Assume everything else to be -0000
15549 else
15551 $timezone = 0;
15554 // Deal with 2 digit year
15555 if ($match[4] < 50)
15557 $match[4] += 2000;
15559 else
15561 $match[4] += 1900;
15564 return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
15566 else
15568 return false;
15573 * Parse C99's asctime()'s date format
15575 * @access protected
15576 * @return int Timestamp
15578 public function date_asctime($date)
15580 static $pcre;
15581 if (!$pcre)
15583 $space = '[\x09\x20]+';
15584 $wday_name = $this->day_pcre;
15585 $mon_name = $this->month_pcre;
15586 $day = '([0-9]{1,2})';
15587 $hour = $sec = $min = '([0-9]{2})';
15588 $year = '([0-9]{4})';
15589 $terminator = '\x0A?\x00?';
15590 $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
15592 if (preg_match($pcre, $date, $match))
15595 Capturing subpatterns:
15596 1: Day name
15597 2: Month
15598 3: Day
15599 4: Hour
15600 5: Minute
15601 6: Second
15602 7: Year
15605 $month = $this->month[strtolower($match[2])];
15606 return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
15608 else
15610 return false;
15615 * Parse dates using strtotime()
15617 * @access protected
15618 * @return int Timestamp
15620 public function date_strtotime($date)
15622 $strtotime = strtotime($date);
15623 if ($strtotime === -1 || $strtotime === false)
15625 return false;
15627 else
15629 return $strtotime;
15635 * Parses XML into something sane
15638 * This class can be overloaded with {@see SimplePie::set_parser_class()}
15640 * @package SimplePie
15641 * @subpackage Parsing
15643 class SimplePie_Parser
15645 var $error_code;
15646 var $error_string;
15647 var $current_line;
15648 var $current_column;
15649 var $current_byte;
15650 var $separator = ' ';
15651 var $namespace = array('');
15652 var $element = array('');
15653 var $xml_base = array('');
15654 var $xml_base_explicit = array(false);
15655 var $xml_lang = array('');
15656 var $data = array();
15657 var $datas = array(array());
15658 var $current_xhtml_construct = -1;
15659 var $encoding;
15660 protected $registry;
15662 public function set_registry(SimplePie_Registry $registry)
15664 $this->registry = $registry;
15667 public function parse(&$data, $encoding)
15669 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
15670 if (strtoupper($encoding) === 'US-ASCII')
15672 $this->encoding = 'UTF-8';
15674 else
15676 $this->encoding = $encoding;
15679 // Strip BOM:
15680 // UTF-32 Big Endian BOM
15681 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
15683 $data = substr($data, 4);
15685 // UTF-32 Little Endian BOM
15686 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
15688 $data = substr($data, 4);
15690 // UTF-16 Big Endian BOM
15691 elseif (substr($data, 0, 2) === "\xFE\xFF")
15693 $data = substr($data, 2);
15695 // UTF-16 Little Endian BOM
15696 elseif (substr($data, 0, 2) === "\xFF\xFE")
15698 $data = substr($data, 2);
15700 // UTF-8 BOM
15701 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
15703 $data = substr($data, 3);
15706 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
15708 $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
15709 if ($declaration->parse())
15711 $data = substr($data, $pos + 2);
15712 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
15714 else
15716 $this->error_string = 'SimplePie bug! Please report this!';
15717 return false;
15721 $return = true;
15723 static $xml_is_sane = null;
15724 if ($xml_is_sane === null)
15726 $parser_check = xml_parser_create();
15727 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
15728 xml_parser_free($parser_check);
15729 $xml_is_sane = isset($values[0]['value']);
15732 // Create the parser
15733 if ($xml_is_sane)
15735 $xml = xml_parser_create_ns($this->encoding, $this->separator);
15736 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
15737 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
15738 xml_set_object($xml, $this);
15739 xml_set_character_data_handler($xml, 'cdata');
15740 xml_set_element_handler($xml, 'tag_open', 'tag_close');
15742 // Parse!
15743 if (!xml_parse($xml, $data, true))
15745 $this->error_code = xml_get_error_code($xml);
15746 $this->error_string = xml_error_string($this->error_code);
15747 $return = false;
15749 $this->current_line = xml_get_current_line_number($xml);
15750 $this->current_column = xml_get_current_column_number($xml);
15751 $this->current_byte = xml_get_current_byte_index($xml);
15752 xml_parser_free($xml);
15753 return $return;
15755 else
15757 libxml_clear_errors();
15758 $xml = new XMLReader();
15759 $xml->xml($data);
15760 while (@$xml->read())
15762 switch ($xml->nodeType)
15765 case constant('XMLReader::END_ELEMENT'):
15766 if ($xml->namespaceURI !== '')
15768 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
15770 else
15772 $tagName = $xml->localName;
15774 $this->tag_close(null, $tagName);
15775 break;
15776 case constant('XMLReader::ELEMENT'):
15777 $empty = $xml->isEmptyElement;
15778 if ($xml->namespaceURI !== '')
15780 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
15782 else
15784 $tagName = $xml->localName;
15786 $attributes = array();
15787 while ($xml->moveToNextAttribute())
15789 if ($xml->namespaceURI !== '')
15791 $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
15793 else
15795 $attrName = $xml->localName;
15797 $attributes[$attrName] = $xml->value;
15799 $this->tag_open(null, $tagName, $attributes);
15800 if ($empty)
15802 $this->tag_close(null, $tagName);
15804 break;
15805 case constant('XMLReader::TEXT'):
15807 case constant('XMLReader::CDATA'):
15808 $this->cdata(null, $xml->value);
15809 break;
15812 if ($error = libxml_get_last_error())
15814 $this->error_code = $error->code;
15815 $this->error_string = $error->message;
15816 $this->current_line = $error->line;
15817 $this->current_column = $error->column;
15818 return false;
15820 else
15822 return true;
15827 public function get_error_code()
15829 return $this->error_code;
15832 public function get_error_string()
15834 return $this->error_string;
15837 public function get_current_line()
15839 return $this->current_line;
15842 public function get_current_column()
15844 return $this->current_column;
15847 public function get_current_byte()
15849 return $this->current_byte;
15852 public function get_data()
15854 return $this->data;
15857 public function tag_open($parser, $tag, $attributes)
15859 list($this->namespace[], $this->element[]) = $this->split_ns($tag);
15861 $attribs = array();
15862 foreach ($attributes as $name => $value)
15864 list($attrib_namespace, $attribute) = $this->split_ns($name);
15865 $attribs[$attrib_namespace][$attribute] = $value;
15868 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
15870 $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
15871 if ($base !== false)
15873 $this->xml_base[] = $base;
15874 $this->xml_base_explicit[] = true;
15877 else
15879 $this->xml_base[] = end($this->xml_base);
15880 $this->xml_base_explicit[] = end($this->xml_base_explicit);
15883 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
15885 $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
15887 else
15889 $this->xml_lang[] = end($this->xml_lang);
15892 if ($this->current_xhtml_construct >= 0)
15894 $this->current_xhtml_construct++;
15895 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
15897 $this->data['data'] .= '<' . end($this->element);
15898 if (isset($attribs['']))
15900 foreach ($attribs[''] as $name => $value)
15902 $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
15905 $this->data['data'] .= '>';
15908 else
15910 $this->datas[] =& $this->data;
15911 $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
15912 $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));
15913 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')
15914 || (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')
15915 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
15916 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
15917 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
15919 $this->current_xhtml_construct = 0;
15924 public function cdata($parser, $cdata)
15926 if ($this->current_xhtml_construct >= 0)
15928 $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
15930 else
15932 $this->data['data'] .= $cdata;
15936 public function tag_close($parser, $tag)
15938 if ($this->current_xhtml_construct >= 0)
15940 $this->current_xhtml_construct--;
15941 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')))
15943 $this->data['data'] .= '</' . end($this->element) . '>';
15946 if ($this->current_xhtml_construct === -1)
15948 $this->data =& $this->datas[count($this->datas) - 1];
15949 array_pop($this->datas);
15952 array_pop($this->element);
15953 array_pop($this->namespace);
15954 array_pop($this->xml_base);
15955 array_pop($this->xml_base_explicit);
15956 array_pop($this->xml_lang);
15959 public function split_ns($string)
15961 static $cache = array();
15962 if (!isset($cache[$string]))
15964 if ($pos = strpos($string, $this->separator))
15966 static $separator_length;
15967 if (!$separator_length)
15969 $separator_length = strlen($this->separator);
15971 $namespace = substr($string, 0, $pos);
15972 $local_name = substr($string, $pos + $separator_length);
15973 if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
15975 $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
15978 // Normalize the Media RSS namespaces
15979 if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
15980 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
15981 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
15982 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
15983 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
15985 $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
15987 $cache[$string] = array($namespace, $local_name);
15989 else
15991 $cache[$string] = array('', $string);
15994 return $cache[$string];
15999 * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
16001 * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
16003 * This class can be overloaded with {@see SimplePie::set_rating_class()}
16005 * @package SimplePie
16006 * @subpackage API
16008 class SimplePie_Rating
16011 * Rating scheme
16013 * @var string
16014 * @see get_scheme()
16016 var $scheme;
16019 * Rating value
16021 * @var string
16022 * @see get_value()
16024 var $value;
16027 * Constructor, used to input the data
16029 * For documentation on all the parameters, see the corresponding
16030 * properties and their accessors
16032 public function __construct($scheme = null, $value = null)
16034 $this->scheme = $scheme;
16035 $this->value = $value;
16039 * String-ified version
16041 * @return string
16043 public function __toString()
16045 // There is no $this->data here
16046 return md5(serialize($this));
16050 * Get the organizational scheme for the rating
16052 * @return string|null
16054 public function get_scheme()
16056 if ($this->scheme !== null)
16058 return $this->scheme;
16060 else
16062 return null;
16067 * Get the value of the rating
16069 * @return string|null
16071 public function get_value()
16073 if ($this->value !== null)
16075 return $this->value;
16077 else
16079 return null;
16085 * Handles creating objects and calling methods
16087 * Access this via {@see SimplePie::get_registry()}
16089 * @package SimplePie
16091 class SimplePie_Registry
16094 * Default class mapping
16096 * Overriding classes *must* subclass these.
16098 * @var array
16100 protected $default = array(
16101 'Cache' => 'SimplePie_Cache',
16102 'Locator' => 'SimplePie_Locator',
16103 'Parser' => 'SimplePie_Parser',
16104 'File' => 'SimplePie_File',
16105 'Sanitize' => 'SimplePie_Sanitize',
16106 'Item' => 'SimplePie_Item',
16107 'Author' => 'SimplePie_Author',
16108 'Category' => 'SimplePie_Category',
16109 'Enclosure' => 'SimplePie_Enclosure',
16110 'Caption' => 'SimplePie_Caption',
16111 'Copyright' => 'SimplePie_Copyright',
16112 'Credit' => 'SimplePie_Credit',
16113 'Rating' => 'SimplePie_Rating',
16114 'Restriction' => 'SimplePie_Restriction',
16115 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
16116 'Source' => 'SimplePie_Source',
16117 'Misc' => 'SimplePie_Misc',
16118 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
16119 'Parse_Date' => 'SimplePie_Parse_Date',
16123 * Class mapping
16125 * @see register()
16126 * @var array
16128 protected $classes = array();
16131 * Legacy classes
16133 * @see register()
16134 * @var array
16136 protected $legacy = array();
16139 * Constructor
16141 * No-op
16143 public function __construct() { }
16146 * Register a class
16148 * @param string $type See {@see $default} for names
16149 * @param string $class Class name, must subclass the corresponding default
16150 * @param bool $legacy Whether to enable legacy support for this class
16151 * @return bool Successfulness
16153 public function register($type, $class, $legacy = false)
16155 if (!is_subclass_of($class, $this->default[$type]))
16157 return false;
16160 $this->classes[$type] = $class;
16162 if ($legacy)
16164 $this->legacy[] = $class;
16167 return true;
16171 * Get the class registered for a type
16173 * Where possible, use {@see create()} or {@see call()} instead
16175 * @param string $type
16176 * @return string|null
16178 public function get_class($type)
16180 if (!empty($this->classes[$type]))
16182 return $this->classes[$type];
16184 if (!empty($this->default[$type]))
16186 return $this->default[$type];
16189 return null;
16193 * Create a new instance of a given type
16195 * @param string $type
16196 * @param array $parameters Parameters to pass to the constructor
16197 * @return object Instance of class
16199 public function &create($type, $parameters = array())
16201 $class = $this->get_class($type);
16203 if (in_array($class, $this->legacy))
16205 switch ($type)
16207 case 'locator':
16208 // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
16209 // Specified: file, timeout, useragent, max_checked_feeds
16210 $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
16211 array_splice($parameters, 3, 1, $replacement);
16212 break;
16216 if (!method_exists($class, '__construct'))
16218 $instance = new $class;
16220 else
16222 $reflector = new ReflectionClass($class);
16223 $instance = $reflector->newInstanceArgs($parameters);
16226 if (method_exists($instance, 'set_registry'))
16228 $instance->set_registry($this);
16230 return $instance;
16234 * Call a static method for a type
16236 * @param string $type
16237 * @param string $method
16238 * @param array $parameters
16239 * @return mixed
16241 public function &call($type, $method, $parameters = array())
16243 $class = $this->get_class($type);
16245 if (in_array($class, $this->legacy))
16247 switch ($type)
16249 case 'Cache':
16250 // For backwards compatibility with old non-static
16251 // Cache::create() methods
16252 if ($method === 'get_handler')
16254 $result = @call_user_func_array(array($class, 'create'), $parameters);
16255 return $result;
16257 break;
16261 $result = call_user_func_array(array($class, $method), $parameters);
16262 return $result;
16267 * Handles `<media:restriction>` as defined in Media RSS
16269 * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
16271 * This class can be overloaded with {@see SimplePie::set_restriction_class()}
16273 * @package SimplePie
16274 * @subpackage API
16276 class SimplePie_Restriction
16279 * Relationship ('allow'/'deny')
16281 * @var string
16282 * @see get_relationship()
16284 var $relationship;
16287 * Type of restriction
16289 * @var string
16290 * @see get_type()
16292 var $type;
16295 * Restricted values
16297 * @var string
16298 * @see get_value()
16300 var $value;
16303 * Constructor, used to input the data
16305 * For documentation on all the parameters, see the corresponding
16306 * properties and their accessors
16308 public function __construct($relationship = null, $type = null, $value = null)
16310 $this->relationship = $relationship;
16311 $this->type = $type;
16312 $this->value = $value;
16316 * String-ified version
16318 * @return string
16320 public function __toString()
16322 // There is no $this->data here
16323 return md5(serialize($this));
16327 * Get the relationship
16329 * @return string|null Either 'allow' or 'deny'
16331 public function get_relationship()
16333 if ($this->relationship !== null)
16335 return $this->relationship;
16337 else
16339 return null;
16344 * Get the type
16346 * @return string|null
16348 public function get_type()
16350 if ($this->type !== null)
16352 return $this->type;
16354 else
16356 return null;
16361 * Get the list of restricted things
16363 * @return string|null
16365 public function get_value()
16367 if ($this->value !== null)
16369 return $this->value;
16371 else
16373 return null;
16379 * Used for data cleanup and post-processing
16382 * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
16384 * @package SimplePie
16385 * @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
16387 class SimplePie_Sanitize
16389 // Private vars
16390 var $base;
16392 // Options
16393 var $remove_div = true;
16394 var $image_handler = '';
16395 var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
16396 var $encode_instead_of_strip = false;
16397 var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
16398 var $strip_comments = false;
16399 var $output_encoding = 'UTF-8';
16400 var $enable_cache = true;
16401 var $cache_location = './cache';
16402 var $cache_name_function = 'md5';
16403 var $timeout = 10;
16404 var $useragent = '';
16405 var $force_fsockopen = false;
16406 var $replace_url_attributes = null;
16408 public function __construct()
16410 // Set defaults
16411 $this->set_url_replacements(null);
16414 public function remove_div($enable = true)
16416 $this->remove_div = (bool) $enable;
16419 public function set_image_handler($page = false)
16421 if ($page)
16423 $this->image_handler = (string) $page;
16425 else
16427 $this->image_handler = false;
16431 public function set_registry(SimplePie_Registry $registry)
16433 $this->registry = $registry;
16436 public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
16438 if (isset($enable_cache))
16440 $this->enable_cache = (bool) $enable_cache;
16443 if ($cache_location)
16445 $this->cache_location = (string) $cache_location;
16448 if ($cache_name_function)
16450 $this->cache_name_function = (string) $cache_name_function;
16454 public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
16456 if ($timeout)
16458 $this->timeout = (string) $timeout;
16461 if ($useragent)
16463 $this->useragent = (string) $useragent;
16466 if ($force_fsockopen)
16468 $this->force_fsockopen = (string) $force_fsockopen;
16472 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'))
16474 if ($tags)
16476 if (is_array($tags))
16478 $this->strip_htmltags = $tags;
16480 else
16482 $this->strip_htmltags = explode(',', $tags);
16485 else
16487 $this->strip_htmltags = false;
16491 public function encode_instead_of_strip($encode = false)
16493 $this->encode_instead_of_strip = (bool) $encode;
16496 public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
16498 if ($attribs)
16500 if (is_array($attribs))
16502 $this->strip_attributes = $attribs;
16504 else
16506 $this->strip_attributes = explode(',', $attribs);
16509 else
16511 $this->strip_attributes = false;
16515 public function strip_comments($strip = false)
16517 $this->strip_comments = (bool) $strip;
16520 public function set_output_encoding($encoding = 'UTF-8')
16522 $this->output_encoding = (string) $encoding;
16526 * Set element/attribute key/value pairs of HTML attributes
16527 * containing URLs that need to be resolved relative to the feed
16529 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
16530 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
16531 * |q|@cite
16533 * @since 1.0
16534 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
16536 public function set_url_replacements($element_attribute = null)
16538 if ($element_attribute === null)
16540 $element_attribute = array(
16541 'a' => 'href',
16542 'area' => 'href',
16543 'blockquote' => 'cite',
16544 'del' => 'cite',
16545 'form' => 'action',
16546 'img' => array(
16547 'longdesc',
16548 'src'
16550 'input' => 'src',
16551 'ins' => 'cite',
16552 'q' => 'cite'
16555 $this->replace_url_attributes = (array) $element_attribute;
16558 public function sanitize($data, $type, $base = '')
16560 $data = trim($data);
16561 if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
16563 if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
16565 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))
16567 $type |= SIMPLEPIE_CONSTRUCT_HTML;
16569 else
16571 $type |= SIMPLEPIE_CONSTRUCT_TEXT;
16575 if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
16577 $data = base64_decode($data);
16580 if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
16582 if (!class_exists('DOMDocument'))
16584 $this->registry->call('Misc', 'error', array('DOMDocument not found, unable to use sanitizer', E_USER_WARNING, __FILE__, __LINE__));
16585 return '';
16587 $document = new DOMDocument();
16588 $document->encoding = 'UTF-8';
16589 $data = $this->preprocess($data, $type);
16591 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
16592 $document->loadHTML($data);
16593 restore_error_handler();
16595 // Strip comments
16596 if ($this->strip_comments)
16598 $xpath = new DOMXPath($document);
16599 $comments = $xpath->query('//comment()');
16601 foreach ($comments as $comment)
16603 $comment->parentNode->removeChild($comment);
16607 // Strip out HTML tags and attributes that might cause various security problems.
16608 // Based on recommendations by Mark Pilgrim at:
16609 // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
16610 if ($this->strip_htmltags)
16612 foreach ($this->strip_htmltags as $tag)
16614 $this->strip_tag($tag, $document, $type);
16618 if ($this->strip_attributes)
16620 foreach ($this->strip_attributes as $attrib)
16622 $this->strip_attr($attrib, $document);
16626 // Replace relative URLs
16627 $this->base = $base;
16628 foreach ($this->replace_url_attributes as $element => $attributes)
16630 $this->replace_urls($document, $element, $attributes);
16633 // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
16634 if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
16636 $images = $document->getElementsByTagName('img');
16637 foreach ($images as $img)
16639 if ($img->hasAttribute('src'))
16641 $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
16642 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
16644 if ($cache->load())
16646 $img->setAttribute('src', $this->image_handler . $image_url);
16648 else
16650 $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));
16651 $headers = $file->headers;
16653 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
16655 if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
16657 $img->setAttribute('src', $this->image_handler . $image_url);
16659 else
16661 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);
16669 // Remove the DOCTYPE
16670 // Seems to cause segfaulting if we don't do this
16671 if ($document->firstChild instanceof DOMDocumentType)
16673 $document->removeChild($document->firstChild);
16676 // Move everything from the body to the root
16677 $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
16678 $document->replaceChild($real_body, $document->firstChild);
16680 // Finally, convert to a HTML string
16681 $data = trim($document->saveHTML());
16683 if ($this->remove_div)
16685 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
16686 $data = preg_replace('/<\/div>$/', '', $data);
16688 else
16690 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
16694 if ($type & SIMPLEPIE_CONSTRUCT_IRI)
16696 $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
16697 if ($absolute !== false)
16699 $data = $absolute;
16703 if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
16705 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
16708 if ($this->output_encoding !== 'UTF-8')
16710 $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
16713 return $data;
16716 protected function preprocess($html, $type)
16718 $ret = '';
16719 if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
16721 // Atom XHTML constructs are wrapped with a div by default
16722 // Note: No protection if $html contains a stray </div>!
16723 $html = '<div>' . $html . '</div>';
16724 $ret .= '<!DOCTYPE html>';
16725 $content_type = 'text/html';
16727 else
16729 $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
16730 $content_type = 'application/xhtml+xml';
16733 $ret .= '<html><head>';
16734 $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
16735 $ret .= '</head><body>' . $html . '</body></html>';
16736 return $ret;
16739 public function replace_urls($document, $tag, $attributes)
16741 if (!is_array($attributes))
16743 $attributes = array($attributes);
16746 if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
16748 $elements = $document->getElementsByTagName($tag);
16749 foreach ($elements as $element)
16751 foreach ($attributes as $attribute)
16753 if ($element->hasAttribute($attribute))
16755 $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
16756 if ($value !== false)
16758 $element->setAttribute($attribute, $value);
16766 public function do_strip_htmltags($match)
16768 if ($this->encode_instead_of_strip)
16770 if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
16772 $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
16773 $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
16774 return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
16776 else
16778 return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
16781 elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
16783 return $match[4];
16785 else
16787 return '';
16791 protected function strip_tag($tag, $document, $type)
16793 $xpath = new DOMXPath($document);
16794 $elements = $xpath->query('body//' . $tag);
16795 if ($this->encode_instead_of_strip)
16797 foreach ($elements as $element)
16799 $fragment = $document->createDocumentFragment();
16801 // For elements which aren't script or style, include the tag itself
16802 if (!in_array($tag, array('script', 'style')))
16804 $text = '<' . $tag;
16805 if ($element->hasAttributes())
16807 $attrs = array();
16808 foreach ($element->attributes as $name => $attr)
16810 $value = $attr->value;
16812 // In XHTML, empty values should never exist, so we repeat the value
16813 if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
16815 $value = $name;
16817 // For HTML, empty is fine
16818 elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
16820 $attrs[] = $name;
16821 continue;
16824 // Standard attribute text
16825 $attrs[] = $name . '="' . $attr->value . '"';
16827 $text .= ' ' . implode(' ', $attrs);
16829 $text .= '>';
16830 $fragment->appendChild(new DOMText($text));
16833 $number = $element->childNodes->length;
16834 for ($i = $number; $i > 0; $i--)
16836 $child = $element->childNodes->item(0);
16837 $fragment->appendChild($child);
16840 if (!in_array($tag, array('script', 'style')))
16842 $fragment->appendChild(new DOMText('</' . $tag . '>'));
16845 $element->parentNode->replaceChild($fragment, $element);
16848 return;
16850 elseif (in_array($tag, array('script', 'style')))
16852 foreach ($elements as $element)
16854 $element->parentNode->removeChild($element);
16857 return;
16859 else
16861 foreach ($elements as $element)
16863 $fragment = $document->createDocumentFragment();
16864 $number = $element->childNodes->length;
16865 for ($i = $number; $i > 0; $i--)
16867 $child = $element->childNodes->item(0);
16868 $fragment->appendChild($child);
16871 $element->parentNode->replaceChild($fragment, $element);
16876 protected function strip_attr($attrib, $document)
16878 $xpath = new DOMXPath($document);
16879 $elements = $xpath->query('//*[@' . $attrib . ']');
16881 foreach ($elements as $element)
16883 $element->removeAttribute($attrib);
16889 * Handles `<atom:source>`
16891 * Used by {@see SimplePie_Item::get_source()}
16893 * This class can be overloaded with {@see SimplePie::set_source_class()}
16895 * @package SimplePie
16896 * @subpackage API
16898 class SimplePie_Source
16900 var $item;
16901 var $data = array();
16902 protected $registry;
16904 public function __construct($item, $data)
16906 $this->item = $item;
16907 $this->data = $data;
16910 public function set_registry(SimplePie_Registry $registry)
16912 $this->registry = $registry;
16915 public function __toString()
16917 return md5(serialize($this->data));
16920 public function get_source_tags($namespace, $tag)
16922 if (isset($this->data['child'][$namespace][$tag]))
16924 return $this->data['child'][$namespace][$tag];
16926 else
16928 return null;
16932 public function get_base($element = array())
16934 return $this->item->get_base($element);
16937 public function sanitize($data, $type, $base = '')
16939 return $this->item->sanitize($data, $type, $base);
16942 public function get_item()
16944 return $this->item;
16947 public function get_title()
16949 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
16951 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16953 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
16955 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16957 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
16959 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16961 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
16963 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16965 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
16967 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16969 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
16971 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
16973 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
16975 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
16977 else
16979 return null;
16983 public function get_category($key = 0)
16985 $categories = $this->get_categories();
16986 if (isset($categories[$key]))
16988 return $categories[$key];
16990 else
16992 return null;
16996 public function get_categories()
16998 $categories = array();
17000 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
17002 $term = null;
17003 $scheme = null;
17004 $label = null;
17005 if (isset($category['attribs']['']['term']))
17007 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
17009 if (isset($category['attribs']['']['scheme']))
17011 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
17013 if (isset($category['attribs']['']['label']))
17015 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
17017 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
17019 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
17021 // This is really the label, but keep this as the term also for BC.
17022 // Label will also work on retrieving because that falls back to term.
17023 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17024 if (isset($category['attribs']['']['domain']))
17026 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
17028 else
17030 $scheme = null;
17032 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
17034 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
17036 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17038 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
17040 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17043 if (!empty($categories))
17045 return array_unique($categories);
17047 else
17049 return null;
17053 public function get_author($key = 0)
17055 $authors = $this->get_authors();
17056 if (isset($authors[$key]))
17058 return $authors[$key];
17060 else
17062 return null;
17066 public function get_authors()
17068 $authors = array();
17069 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
17071 $name = null;
17072 $uri = null;
17073 $email = null;
17074 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
17076 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17078 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
17080 $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]));
17082 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
17084 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17086 if ($name !== null || $email !== null || $uri !== null)
17088 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
17091 if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
17093 $name = null;
17094 $url = null;
17095 $email = null;
17096 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
17098 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17100 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
17102 $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]));
17104 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17106 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17108 if ($name !== null || $email !== null || $url !== null)
17110 $authors[] = $this->registry->create('Author', array($name, $url, $email));
17113 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
17115 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17117 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
17119 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17121 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
17123 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17126 if (!empty($authors))
17128 return array_unique($authors);
17130 else
17132 return null;
17136 public function get_contributor($key = 0)
17138 $contributors = $this->get_contributors();
17139 if (isset($contributors[$key]))
17141 return $contributors[$key];
17143 else
17145 return null;
17149 public function get_contributors()
17151 $contributors = array();
17152 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
17154 $name = null;
17155 $uri = null;
17156 $email = null;
17157 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
17159 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17161 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
17163 $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]));
17165 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
17167 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17169 if ($name !== null || $email !== null || $uri !== null)
17171 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
17174 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
17176 $name = null;
17177 $url = null;
17178 $email = null;
17179 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
17181 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17183 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
17185 $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]));
17187 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17189 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17191 if ($name !== null || $email !== null || $url !== null)
17193 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
17197 if (!empty($contributors))
17199 return array_unique($contributors);
17201 else
17203 return null;
17207 public function get_link($key = 0, $rel = 'alternate')
17209 $links = $this->get_links($rel);
17210 if (isset($links[$key]))
17212 return $links[$key];
17214 else
17216 return null;
17221 * Added for parity between the parent-level and the item/entry-level.
17223 public function get_permalink()
17225 return $this->get_link(0);
17228 public function get_links($rel = 'alternate')
17230 if (!isset($this->data['links']))
17232 $this->data['links'] = array();
17233 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
17235 foreach ($links as $link)
17237 if (isset($link['attribs']['']['href']))
17239 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
17240 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
17244 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
17246 foreach ($links as $link)
17248 if (isset($link['attribs']['']['href']))
17250 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
17251 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
17256 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
17258 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17260 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
17262 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17264 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
17266 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17269 $keys = array_keys($this->data['links']);
17270 foreach ($keys as $key)
17272 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
17274 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
17276 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
17277 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
17279 else
17281 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
17284 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
17286 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
17288 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
17292 if (isset($this->data['links'][$rel]))
17294 return $this->data['links'][$rel];
17296 else
17298 return null;
17302 public function get_description()
17304 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
17306 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17308 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
17310 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17312 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
17314 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17316 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
17318 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17320 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
17322 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17324 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
17326 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17328 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
17330 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17332 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
17334 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
17336 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
17338 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
17340 else
17342 return null;
17346 public function get_copyright()
17348 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
17350 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17352 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
17354 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17356 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
17358 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17360 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
17362 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17364 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
17366 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17368 else
17370 return null;
17374 public function get_language()
17376 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
17378 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17380 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
17382 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17384 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
17386 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17388 elseif (isset($this->data['xml_lang']))
17390 return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
17392 else
17394 return null;
17398 public function get_latitude()
17400 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
17402 return (float) $return[0]['data'];
17404 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))
17406 return (float) $match[1];
17408 else
17410 return null;
17414 public function get_longitude()
17416 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
17418 return (float) $return[0]['data'];
17420 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
17422 return (float) $return[0]['data'];
17424 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))
17426 return (float) $match[2];
17428 else
17430 return null;
17434 public function get_image_url()
17436 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
17438 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
17440 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
17442 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
17444 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
17446 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
17448 else
17450 return null;
17456 * Parses the XML Declaration
17458 * @package SimplePie
17459 * @subpackage Parsing
17461 class SimplePie_XML_Declaration_Parser
17464 * XML Version
17466 * @access public
17467 * @var string
17469 var $version = '1.0';
17472 * Encoding
17474 * @access public
17475 * @var string
17477 var $encoding = 'UTF-8';
17480 * Standalone
17482 * @access public
17483 * @var bool
17485 var $standalone = false;
17488 * Current state of the state machine
17490 * @access private
17491 * @var string
17493 var $state = 'before_version_name';
17496 * Input data
17498 * @access private
17499 * @var string
17501 var $data = '';
17504 * Input data length (to avoid calling strlen() everytime this is needed)
17506 * @access private
17507 * @var int
17509 var $data_length = 0;
17512 * Current position of the pointer
17514 * @var int
17515 * @access private
17517 var $position = 0;
17520 * Create an instance of the class with the input data
17522 * @access public
17523 * @param string $data Input data
17525 public function __construct($data)
17527 $this->data = $data;
17528 $this->data_length = strlen($this->data);
17532 * Parse the input data
17534 * @access public
17535 * @return bool true on success, false on failure
17537 public function parse()
17539 while ($this->state && $this->state !== 'emit' && $this->has_data())
17541 $state = $this->state;
17542 $this->$state();
17544 $this->data = '';
17545 if ($this->state === 'emit')
17547 return true;
17549 else
17551 $this->version = '';
17552 $this->encoding = '';
17553 $this->standalone = '';
17554 return false;
17559 * Check whether there is data beyond the pointer
17561 * @access private
17562 * @return bool true if there is further data, false if not
17564 public function has_data()
17566 return (bool) ($this->position < $this->data_length);
17570 * Advance past any whitespace
17572 * @return int Number of whitespace characters passed
17574 public function skip_whitespace()
17576 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
17577 $this->position += $whitespace;
17578 return $whitespace;
17582 * Read value
17584 public function get_value()
17586 $quote = substr($this->data, $this->position, 1);
17587 if ($quote === '"' || $quote === "'")
17589 $this->position++;
17590 $len = strcspn($this->data, $quote, $this->position);
17591 if ($this->has_data())
17593 $value = substr($this->data, $this->position, $len);
17594 $this->position += $len + 1;
17595 return $value;
17598 return false;
17601 public function before_version_name()
17603 if ($this->skip_whitespace())
17605 $this->state = 'version_name';
17607 else
17609 $this->state = false;
17613 public function version_name()
17615 if (substr($this->data, $this->position, 7) === 'version')
17617 $this->position += 7;
17618 $this->skip_whitespace();
17619 $this->state = 'version_equals';
17621 else
17623 $this->state = false;
17627 public function version_equals()
17629 if (substr($this->data, $this->position, 1) === '=')
17631 $this->position++;
17632 $this->skip_whitespace();
17633 $this->state = 'version_value';
17635 else
17637 $this->state = false;
17641 public function version_value()
17643 if ($this->version = $this->get_value())
17645 $this->skip_whitespace();
17646 if ($this->has_data())
17648 $this->state = 'encoding_name';
17650 else
17652 $this->state = 'emit';
17655 else
17657 $this->state = false;
17661 public function encoding_name()
17663 if (substr($this->data, $this->position, 8) === 'encoding')
17665 $this->position += 8;
17666 $this->skip_whitespace();
17667 $this->state = 'encoding_equals';
17669 else
17671 $this->state = 'standalone_name';
17675 public function encoding_equals()
17677 if (substr($this->data, $this->position, 1) === '=')
17679 $this->position++;
17680 $this->skip_whitespace();
17681 $this->state = 'encoding_value';
17683 else
17685 $this->state = false;
17689 public function encoding_value()
17691 if ($this->encoding = $this->get_value())
17693 $this->skip_whitespace();
17694 if ($this->has_data())
17696 $this->state = 'standalone_name';
17698 else
17700 $this->state = 'emit';
17703 else
17705 $this->state = false;
17709 public function standalone_name()
17711 if (substr($this->data, $this->position, 10) === 'standalone')
17713 $this->position += 10;
17714 $this->skip_whitespace();
17715 $this->state = 'standalone_equals';
17717 else
17719 $this->state = false;
17723 public function standalone_equals()
17725 if (substr($this->data, $this->position, 1) === '=')
17727 $this->position++;
17728 $this->skip_whitespace();
17729 $this->state = 'standalone_value';
17731 else
17733 $this->state = false;
17737 public function standalone_value()
17739 if ($standalone = $this->get_value())
17741 switch ($standalone)
17743 case 'yes':
17744 $this->standalone = true;
17745 break;
17747 case 'no':
17748 $this->standalone = false;
17749 break;
17751 default:
17752 $this->state = false;
17753 return;
17756 $this->skip_whitespace();
17757 if ($this->has_data())
17759 $this->state = false;
17761 else
17763 $this->state = 'emit';
17766 else
17768 $this->state = false;