]> git.wh0rd.org Git - tt-rss.git/blob - lib/simplepie/simplepie.inc
remove twitter-specific code
[tt-rss.git] / lib / simplepie / simplepie.inc
1 <?php
2 /**
3  * SimplePie
4  *
5  * A PHP-Based RSS and Atom Feed Framework.
6  * Takes the hard work out of managing a complete RSS/Atom solution.
7  *
8  * Copyright (c) 2004-2011, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without modification, are
12  * permitted provided that the following conditions are met:
13  *
14  *      * Redistributions of source code must retain the above copyright notice, this list of
15  *        conditions and the following disclaimer.
16  *
17  *      * Redistributions in binary form must reproduce the above copyright notice, this list
18  *        of conditions and the following disclaimer in the documentation and/or other materials
19  *        provided with the distribution.
20  *
21  *      * Neither the name of the SimplePie Team nor the names of its contributors may be used
22  *        to endorse or promote products derived from this software without specific prior
23  *        written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28  * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * @package SimplePie
36  * @version 1.2.1
37  * @copyright 2004-2011 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38  * @author Ryan Parman
39  * @author Geoffrey Sneddon
40  * @author Ryan McCue
41  * @link http://simplepie.org/ SimplePie
42  * @link http://simplepie.org/support/ Please submit all bug reports and feature requests to the SimplePie forums
43  * @license http://www.opensource.org/licenses/bsd-license.php BSD License
44  * @todo phpDoc comments
45  */
46
47 /**
48  * SimplePie Name
49  */
50 define('SIMPLEPIE_NAME', 'SimplePie');
51
52 /**
53  * SimplePie Version
54  */
55 define('SIMPLEPIE_VERSION', '1.2.1-dev');
56
57 /**
58  * SimplePie Build
59  */
60 define('SIMPLEPIE_BUILD', '20111015034325');
61
62 /**
63  * SimplePie Website URL
64  */
65 define('SIMPLEPIE_URL', 'http://simplepie.org');
66
67 /**
68  * SimplePie Useragent
69  * @see SimplePie::set_useragent()
70  */
71 define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
72
73 /**
74  * SimplePie Linkback
75  */
76 define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
77
78 /**
79  * No Autodiscovery
80  * @see SimplePie::set_autodiscovery_level()
81  */
82 define('SIMPLEPIE_LOCATOR_NONE', 0);
83
84 /**
85  * Feed Link Element Autodiscovery
86  * @see SimplePie::set_autodiscovery_level()
87  */
88 define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
89
90 /**
91  * Local Feed Extension Autodiscovery
92  * @see SimplePie::set_autodiscovery_level()
93  */
94 define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
95
96 /**
97  * Local Feed Body Autodiscovery
98  * @see SimplePie::set_autodiscovery_level()
99  */
100 define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
101
102 /**
103  * Remote Feed Extension Autodiscovery
104  * @see SimplePie::set_autodiscovery_level()
105  */
106 define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
107
108 /**
109  * Remote Feed Body Autodiscovery
110  * @see SimplePie::set_autodiscovery_level()
111  */
112 define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
113
114 /**
115  * All Feed Autodiscovery
116  * @see SimplePie::set_autodiscovery_level()
117  */
118 define('SIMPLEPIE_LOCATOR_ALL', 31);
119
120 /**
121  * No known feed type
122  */
123 define('SIMPLEPIE_TYPE_NONE', 0);
124
125 /**
126  * RSS 0.90
127  */
128 define('SIMPLEPIE_TYPE_RSS_090', 1);
129
130 /**
131  * RSS 0.91 (Netscape)
132  */
133 define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
134
135 /**
136  * RSS 0.91 (Userland)
137  */
138 define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
139
140 /**
141  * RSS 0.91 (both Netscape and Userland)
142  */
143 define('SIMPLEPIE_TYPE_RSS_091', 6);
144
145 /**
146  * RSS 0.92
147  */
148 define('SIMPLEPIE_TYPE_RSS_092', 8);
149
150 /**
151  * RSS 0.93
152  */
153 define('SIMPLEPIE_TYPE_RSS_093', 16);
154
155 /**
156  * RSS 0.94
157  */
158 define('SIMPLEPIE_TYPE_RSS_094', 32);
159
160 /**
161  * RSS 1.0
162  */
163 define('SIMPLEPIE_TYPE_RSS_10', 64);
164
165 /**
166  * RSS 2.0
167  */
168 define('SIMPLEPIE_TYPE_RSS_20', 128);
169
170 /**
171  * RDF-based RSS
172  */
173 define('SIMPLEPIE_TYPE_RSS_RDF', 65);
174
175 /**
176  * Non-RDF-based RSS (truly intended as syndication format)
177  */
178 define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
179
180 /**
181  * All RSS
182  */
183 define('SIMPLEPIE_TYPE_RSS_ALL', 255);
184
185 /**
186  * Atom 0.3
187  */
188 define('SIMPLEPIE_TYPE_ATOM_03', 256);
189
190 /**
191  * Atom 1.0
192  */
193 define('SIMPLEPIE_TYPE_ATOM_10', 512);
194
195 /**
196  * All Atom
197  */
198 define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
199
200 /**
201  * All feed types
202  */
203 define('SIMPLEPIE_TYPE_ALL', 1023);
204
205 /**
206  * No construct
207  */
208 define('SIMPLEPIE_CONSTRUCT_NONE', 0);
209
210 /**
211  * Text construct
212  */
213 define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
214
215 /**
216  * HTML construct
217  */
218 define('SIMPLEPIE_CONSTRUCT_HTML', 2);
219
220 /**
221  * XHTML construct
222  */
223 define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
224
225 /**
226  * base64-encoded construct
227  */
228 define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
229
230 /**
231  * IRI construct
232  */
233 define('SIMPLEPIE_CONSTRUCT_IRI', 16);
234
235 /**
236  * A construct that might be HTML
237  */
238 define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
239
240 /**
241  * All constructs
242  */
243 define('SIMPLEPIE_CONSTRUCT_ALL', 63);
244
245 /**
246  * Don't change case
247  */
248 define('SIMPLEPIE_SAME_CASE', 1);
249
250 /**
251  * Change to lowercase
252  */
253 define('SIMPLEPIE_LOWERCASE', 2);
254
255 /**
256  * Change to uppercase
257  */
258 define('SIMPLEPIE_UPPERCASE', 4);
259
260 /**
261  * PCRE for HTML attributes
262  */
263 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]*');
264
265 /**
266  * PCRE for XML attributes
267  */
268 define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
269
270 /**
271  * XML Namespace
272  */
273 define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
274
275 /**
276  * Atom 1.0 Namespace
277  */
278 define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
279
280 /**
281  * Atom 0.3 Namespace
282  */
283 define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
284
285 /**
286  * RDF Namespace
287  */
288 define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
289
290 /**
291  * RSS 0.90 Namespace
292  */
293 define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
294
295 /**
296  * RSS 1.0 Namespace
297  */
298 define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
299
300 /**
301  * RSS 1.0 Content Module Namespace
302  */
303 define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
304
305 /**
306  * RSS 2.0 Namespace
307  * (Stupid, I know, but I'm certain it will confuse people less with support.)
308  */
309 define('SIMPLEPIE_NAMESPACE_RSS_20', '');
310
311 /**
312  * DC 1.0 Namespace
313  */
314 define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
315
316 /**
317  * DC 1.1 Namespace
318  */
319 define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
320
321 /**
322  * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
323  */
324 define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
325
326 /**
327  * GeoRSS Namespace
328  */
329 define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
330
331 /**
332  * Media RSS Namespace
333  */
334 define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
335
336 /**
337  * Wrong Media RSS Namespace
338  */
339 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
340
341 /**
342  * iTunes RSS Namespace
343  */
344 define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
345
346 /**
347  * XHTML Namespace
348  */
349 define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
350
351 /**
352  * IANA Link Relations Registry
353  */
354 define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
355
356 /**
357  * Whether we're running on PHP5
358  */
359 define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>='));
360
361 /**
362  * No file source
363  */
364 define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
365
366 /**
367  * Remote file source
368  */
369 define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
370
371 /**
372  * Local file source
373  */
374 define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
375
376 /**
377  * fsockopen() file source
378  */
379 define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
380
381 /**
382  * cURL file source
383  */
384 define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
385
386 /**
387  * file_get_contents() file source
388  */
389 define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
390
391 /**
392  * SimplePie
393  *
394  * @package SimplePie
395  */
396 class SimplePie
397 {
398         /**
399          * @var array Raw data
400          * @access private
401          */
402         var $data = array();
403
404         /**
405          * @var mixed Error string
406          * @access private
407          */
408         var $error;
409
410         /**
411          * @var object Instance of SimplePie_Sanitize (or other class)
412          * @see SimplePie::set_sanitize_class()
413          * @access private
414          */
415         var $sanitize;
416
417         /**
418          * @var string SimplePie Useragent
419          * @see SimplePie::set_useragent()
420          * @access private
421          */
422         var $useragent = SIMPLEPIE_USERAGENT;
423
424         /**
425          * @var string Feed URL
426          * @see SimplePie::set_feed_url()
427          * @access private
428          */
429         var $feed_url;
430
431         /**
432          * @var object Instance of SimplePie_File to use as a feed
433          * @see SimplePie::set_file()
434          * @access private
435          */
436         var $file;
437
438         /**
439          * @var string Raw feed data
440          * @see SimplePie::set_raw_data()
441          * @access private
442          */
443         var $raw_data;
444
445         /**
446          * @var int Timeout for fetching remote files
447          * @see SimplePie::set_timeout()
448          * @access private
449          */
450         var $timeout = 10;
451
452         /**
453          * @var bool Forces fsockopen() to be used for remote files instead
454          * of cURL, even if a new enough version is installed
455          * @see SimplePie::force_fsockopen()
456          * @access private
457          */
458         var $force_fsockopen = false;
459
460         /**
461          * @var bool Force the given data/URL to be treated as a feed no matter what
462          * it appears like
463          * @see SimplePie::force_feed()
464          * @access private
465          */
466         var $force_feed = false;
467
468         /**
469          * @var bool Enable/Disable XML dump
470          * @see SimplePie::enable_xml_dump()
471          * @access private
472          */
473         var $xml_dump = false;
474
475         /**
476          * @var bool Enable/Disable Caching
477          * @see SimplePie::enable_cache()
478          * @access private
479          */
480         var $cache = true;
481
482         /**
483          * @var int Cache duration (in seconds)
484          * @see SimplePie::set_cache_duration()
485          * @access private
486          */
487         var $cache_duration = 3600;
488
489         /**
490          * @var int Auto-discovery cache duration (in seconds)
491          * @see SimplePie::set_autodiscovery_cache_duration()
492          * @access private
493          */
494         var $autodiscovery_cache_duration = 604800; // 7 Days.
495
496         /**
497          * @var string Cache location (relative to executing script)
498          * @see SimplePie::set_cache_location()
499          * @access private
500          */
501         var $cache_location = './cache';
502
503         /**
504          * @var string Function that creates the cache filename
505          * @see SimplePie::set_cache_name_function()
506          * @access private
507          */
508         var $cache_name_function = 'md5';
509
510         /**
511          * @var bool Reorder feed by date descending
512          * @see SimplePie::enable_order_by_date()
513          * @access private
514          */
515         var $order_by_date = true;
516
517         /**
518          * @var mixed Force input encoding to be set to the follow value
519          * (false, or anything type-cast to false, disables this feature)
520          * @see SimplePie::set_input_encoding()
521          * @access private
522          */
523         var $input_encoding = false;
524
525         /**
526          * @var int Feed Autodiscovery Level
527          * @see SimplePie::set_autodiscovery_level()
528          * @access private
529          */
530         var $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
531
532         /**
533          * @var string Class used for caching feeds
534          * @see SimplePie::set_cache_class()
535          * @access private
536          */
537         var $cache_class = 'SimplePie_Cache';
538
539         /**
540          * @var string Class used for locating feeds
541          * @see SimplePie::set_locator_class()
542          * @access private
543          */
544         var $locator_class = 'SimplePie_Locator';
545
546         /**
547          * @var string Class used for parsing feeds
548          * @see SimplePie::set_parser_class()
549          * @access private
550          */
551         var $parser_class = 'SimplePie_Parser';
552
553         /**
554          * @var string Class used for fetching feeds
555          * @see SimplePie::set_file_class()
556          * @access private
557          */
558         var $file_class = 'SimplePie_File';
559
560         /**
561          * @var string Class used for items
562          * @see SimplePie::set_item_class()
563          * @access private
564          */
565         var $item_class = 'SimplePie_Item';
566
567         /**
568          * @var string Class used for authors
569          * @see SimplePie::set_author_class()
570          * @access private
571          */
572         var $author_class = 'SimplePie_Author';
573
574         /**
575          * @var string Class used for categories
576          * @see SimplePie::set_category_class()
577          * @access private
578          */
579         var $category_class = 'SimplePie_Category';
580
581         /**
582          * @var string Class used for enclosures
583          * @see SimplePie::set_enclosures_class()
584          * @access private
585          */
586         var $enclosure_class = 'SimplePie_Enclosure';
587
588         /**
589          * @var string Class used for Media RSS <media:text> captions
590          * @see SimplePie::set_caption_class()
591          * @access private
592          */
593         var $caption_class = 'SimplePie_Caption';
594
595         /**
596          * @var string Class used for Media RSS <media:copyright>
597          * @see SimplePie::set_copyright_class()
598          * @access private
599          */
600         var $copyright_class = 'SimplePie_Copyright';
601
602         /**
603          * @var string Class used for Media RSS <media:credit>
604          * @see SimplePie::set_credit_class()
605          * @access private
606          */
607         var $credit_class = 'SimplePie_Credit';
608
609         /**
610          * @var string Class used for Media RSS <media:rating>
611          * @see SimplePie::set_rating_class()
612          * @access private
613          */
614         var $rating_class = 'SimplePie_Rating';
615
616         /**
617          * @var string Class used for Media RSS <media:restriction>
618          * @see SimplePie::set_restriction_class()
619          * @access private
620          */
621         var $restriction_class = 'SimplePie_Restriction';
622
623         /**
624          * @var string Class used for content-type sniffing
625          * @see SimplePie::set_content_type_sniffer_class()
626          * @access private
627          */
628         var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
629
630         /**
631          * @var string Class used for item sources.
632          * @see SimplePie::set_source_class()
633          * @access private
634          */
635         var $source_class = 'SimplePie_Source';
636
637         /**
638          * @var mixed Set javascript query string parameter (false, or
639          * anything type-cast to false, disables this feature)
640          * @see SimplePie::set_javascript()
641          * @access private
642          */
643         var $javascript = 'js';
644
645         /**
646          * @var int Maximum number of feeds to check with autodiscovery
647          * @see SimplePie::set_max_checked_feeds()
648          * @access private
649          */
650         var $max_checked_feeds = 10;
651
652         /**
653          * @var array All the feeds found during the autodiscovery process
654          * @see SimplePie::get_all_discovered_feeds()
655          * @access private
656          */
657         var $all_discovered_feeds = array();
658
659         /**
660          * @var string Web-accessible path to the handler_favicon.php file.
661          * @see SimplePie::set_favicon_handler()
662          * @access private
663          */
664         var $favicon_handler = '';
665
666         /**
667          * @var string Web-accessible path to the handler_image.php file.
668          * @see SimplePie::set_image_handler()
669          * @access private
670          */
671         var $image_handler = '';
672
673         /**
674          * @var array Stores the URLs when multiple feeds are being initialized.
675          * @see SimplePie::set_feed_url()
676          * @access private
677          */
678         var $multifeed_url = array();
679
680         /**
681          * @var array Stores SimplePie objects when multiple feeds initialized.
682          * @access private
683          */
684         var $multifeed_objects = array();
685
686         /**
687          * @var array Stores the get_object_vars() array for use with multifeeds.
688          * @see SimplePie::set_feed_url()
689          * @access private
690          */
691         var $config_settings = null;
692
693         /**
694          * @var integer Stores the number of items to return per-feed with multifeeds.
695          * @see SimplePie::set_item_limit()
696          * @access private
697          */
698         var $item_limit = 0;
699
700         /**
701          * @var array Stores the default attributes to be stripped by strip_attributes().
702          * @see SimplePie::strip_attributes()
703          * @access private
704          */
705         var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
706
707         /**
708          * @var array Stores the default tags to be stripped by strip_htmltags().
709          * @see SimplePie::strip_htmltags()
710          * @access private
711          */
712         var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
713
714         /**
715          * The SimplePie class contains feed level data and options
716          *
717          * There are two ways that you can create a new SimplePie object. The first
718          * is by passing a feed URL as a parameter to the SimplePie constructor
719          * (as well as optionally setting the cache location and cache expiry). This
720          * will initialise the whole feed with all of the default settings, and you
721          * can begin accessing methods and properties immediately.
722          *
723          * The second way is to create the SimplePie object with no parameters
724          * at all. This will enable you to set configuration options. After setting
725          * them, you must initialise the feed using $feed->init(). At that point the
726          * object's methods and properties will be available to you. This format is
727          * what is used throughout this documentation.
728          *
729          * @access public
730          * @since 1.0 Preview Release
731          * @param string $feed_url This is the URL you want to parse.
732          * @param string $cache_location This is where you want the cache to be stored.
733          * @param int $cache_duration This is the number of seconds that you want to store the cache file for.
734          */
735         function SimplePie($feed_url = null, $cache_location = null, $cache_duration = null)
736         {
737                 // Other objects, instances created here so we can set options on them
738                 $this->sanitize =& new SimplePie_Sanitize;
739
740                 // Set options if they're passed to the constructor
741                 if ($cache_location !== null)
742                 {
743                         $this->set_cache_location($cache_location);
744                 }
745
746                 if ($cache_duration !== null)
747                 {
748                         $this->set_cache_duration($cache_duration);
749                 }
750
751                 // Only init the script if we're passed a feed URL
752                 if ($feed_url !== null)
753                 {
754                         $this->set_feed_url($feed_url);
755                         $this->init();
756                 }
757         }
758
759         /**
760          * Used for converting object to a string
761          */
762         function __toString()
763         {
764                 return md5(serialize($this->data));
765         }
766
767         /**
768          * Remove items that link back to this before destroying this object
769          */
770         function __destruct()
771         {
772                 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
773                 {
774                         if (!empty($this->data['items']))
775                         {
776                                 foreach ($this->data['items'] as $item)
777                                 {
778                                         $item->__destruct();
779                                 }
780                                 unset($item, $this->data['items']);
781                         }
782                         if (!empty($this->data['ordered_items']))
783                         {
784                                 foreach ($this->data['ordered_items'] as $item)
785                                 {
786                                         $item->__destruct();
787                                 }
788                                 unset($item, $this->data['ordered_items']);
789                         }
790                 }
791         }
792
793         /**
794          * Force the given data/URL to be treated as a feed no matter what it
795          * appears like
796          *
797          * @access public
798          * @since 1.1
799          * @param bool $enable Force the given data/URL to be treated as a feed
800          */
801         function force_feed($enable = false)
802         {
803                 $this->force_feed = (bool) $enable;
804         }
805
806         /**
807          * This is the URL of the feed you want to parse.
808          *
809          * This allows you to enter the URL of the feed you want to parse, or the
810          * website you want to try to use auto-discovery on. This takes priority
811          * over any set raw data.
812          *
813          * You can set multiple feeds to mash together by passing an array instead
814          * of a string for the $url. Remember that with each additional feed comes
815          * additional processing and resources.
816          *
817          * @access public
818          * @since 1.0 Preview Release
819          * @param mixed $url This is the URL (or array of URLs) that you want to parse.
820          * @see SimplePie::set_raw_data()
821          */
822         function set_feed_url($url)
823         {
824                 if (is_array($url))
825                 {
826                         $this->multifeed_url = array();
827                         foreach ($url as $value)
828                         {
829                                 $this->multifeed_url[] = SimplePie_Misc::fix_protocol($value, 1);
830                         }
831                 }
832                 else
833                 {
834                         $this->feed_url = SimplePie_Misc::fix_protocol($url, 1);
835                 }
836         }
837
838         /**
839          * Provides an instance of SimplePie_File to use as a feed
840          *
841          * @access public
842          * @param object &$file Instance of SimplePie_File (or subclass)
843          * @return bool True on success, false on failure
844          */
845         function set_file(&$file)
846         {
847                 if (is_a($file, 'SimplePie_File'))
848                 {
849                         $this->feed_url = $file->url;
850                         $this->file =& $file;
851                         return true;
852                 }
853                 return false;
854         }
855
856         /**
857          * Allows you to use a string of RSS/Atom data instead of a remote feed.
858          *
859          * If you have a feed available as a string in PHP, you can tell SimplePie
860          * to parse that data string instead of a remote feed. Any set feed URL
861          * takes precedence.
862          *
863          * @access public
864          * @since 1.0 Beta 3
865          * @param string $data RSS or Atom data as a string.
866          * @see SimplePie::set_feed_url()
867          */
868         function set_raw_data($data)
869         {
870                 $this->raw_data = $data;
871         }
872
873         /**
874          * Allows you to override the default timeout for fetching remote feeds.
875          *
876          * This allows you to change the maximum time the feed's server to respond
877          * and send the feed back.
878          *
879          * @access public
880          * @since 1.0 Beta 3
881          * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
882          */
883         function set_timeout($timeout = 10)
884         {
885                 $this->timeout = (int) $timeout;
886         }
887
888         /**
889          * Forces SimplePie to use fsockopen() instead of the preferred cURL
890          * functions.
891          *
892          * @access public
893          * @since 1.0 Beta 3
894          * @param bool $enable Force fsockopen() to be used
895          */
896         function force_fsockopen($enable = false)
897         {
898                 $this->force_fsockopen = (bool) $enable;
899         }
900
901         /**
902          * Outputs the raw XML content of the feed, after it has gone through
903          * SimplePie's filters.
904          *
905          * Used only for debugging, this function will output the XML content as
906          * text/xml. When SimplePie reads in a feed, it does a bit of cleaning up
907          * before trying to parse it. Many parts of the feed are re-written in
908          * memory, and in the end, you have a parsable feed. XML dump shows you the
909          * actual XML that SimplePie tries to parse, which may or may not be very
910          * different from the original feed.
911          *
912          * @access public
913          * @since 1.0 Preview Release
914          * @param bool $enable Enable XML dump
915          */
916         function enable_xml_dump($enable = false)
917         {
918                 $this->xml_dump = (bool) $enable;
919         }
920
921         /**
922          * Enables/disables caching in SimplePie.
923          *
924          * This option allows you to disable caching all-together in SimplePie.
925          * However, disabling the cache can lead to longer load times.
926          *
927          * @access public
928          * @since 1.0 Preview Release
929          * @param bool $enable Enable caching
930          */
931         function enable_cache($enable = true)
932         {
933                 $this->cache = (bool) $enable;
934         }
935
936         /**
937          * Set the length of time (in seconds) that the contents of a feed
938          * will be cached.
939          *
940          * @access public
941          * @param int $seconds The feed content cache duration.
942          */
943         function set_cache_duration($seconds = 3600)
944         {
945                 $this->cache_duration = (int) $seconds;
946         }
947
948         /**
949          * Set the length of time (in seconds) that the autodiscovered feed
950          * URL will be cached.
951          *
952          * @access public
953          * @param int $seconds The autodiscovered feed URL cache duration.
954          */
955         function set_autodiscovery_cache_duration($seconds = 604800)
956         {
957                 $this->autodiscovery_cache_duration = (int) $seconds;
958         }
959
960         /**
961          * Set the file system location where the cached files should be stored.
962          *
963          * @access public
964          * @param string $location The file system location.
965          */
966         function set_cache_location($location = './cache')
967         {
968                 $this->cache_location = (string) $location;
969         }
970
971         /**
972          * Determines whether feed items should be sorted into reverse chronological order.
973          *
974          * @access public
975          * @param bool $enable Sort as reverse chronological order.
976          */
977         function enable_order_by_date($enable = true)
978         {
979                 $this->order_by_date = (bool) $enable;
980         }
981
982         /**
983          * Allows you to override the character encoding reported by the feed.
984          *
985          * @access public
986          * @param string $encoding Character encoding.
987          */
988         function set_input_encoding($encoding = false)
989         {
990                 if ($encoding)
991                 {
992                         $this->input_encoding = (string) $encoding;
993                 }
994                 else
995                 {
996                         $this->input_encoding = false;
997                 }
998         }
999
1000         /**
1001          * Set how much feed autodiscovery to do
1002          *
1003          * @access public
1004          * @see SIMPLEPIE_LOCATOR_NONE
1005          * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
1006          * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
1007          * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
1008          * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
1009          * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
1010          * @see SIMPLEPIE_LOCATOR_ALL
1011          * @param int $level Feed Autodiscovery Level (level can be a
1012          * combination of the above constants, see bitwise OR operator)
1013          */
1014         function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
1015         {
1016                 $this->autodiscovery = (int) $level;
1017         }
1018
1019         /**
1020          * Allows you to change which class SimplePie uses for caching.
1021          * Useful when you are overloading or extending SimplePie's default classes.
1022          *
1023          * @access public
1024          * @param string $class Name of custom class.
1025          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1026          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1027          */
1028         function set_cache_class($class = 'SimplePie_Cache')
1029         {
1030                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Cache'))
1031                 {
1032                         $this->cache_class = $class;
1033                         return true;
1034                 }
1035                 return false;
1036         }
1037
1038         /**
1039          * Allows you to change which class SimplePie uses for auto-discovery.
1040          * Useful when you are overloading or extending SimplePie's default classes.
1041          *
1042          * @access public
1043          * @param string $class Name of custom class.
1044          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1045          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1046          */
1047         function set_locator_class($class = 'SimplePie_Locator')
1048         {
1049                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Locator'))
1050                 {
1051                         $this->locator_class = $class;
1052                         return true;
1053                 }
1054                 return false;
1055         }
1056
1057         /**
1058          * Allows you to change which class SimplePie uses for XML parsing.
1059          * Useful when you are overloading or extending SimplePie's default classes.
1060          *
1061          * @access public
1062          * @param string $class Name of custom class.
1063          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1064          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1065          */
1066         function set_parser_class($class = 'SimplePie_Parser')
1067         {
1068                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser'))
1069                 {
1070                         $this->parser_class = $class;
1071                         return true;
1072                 }
1073                 return false;
1074         }
1075
1076         /**
1077          * Allows you to change which class SimplePie uses for remote file fetching.
1078          * Useful when you are overloading or extending SimplePie's default classes.
1079          *
1080          * @access public
1081          * @param string $class Name of custom class.
1082          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1083          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1084          */
1085         function set_file_class($class = 'SimplePie_File')
1086         {
1087                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_File'))
1088                 {
1089                         $this->file_class = $class;
1090                         return true;
1091                 }
1092                 return false;
1093         }
1094
1095         /**
1096          * Allows you to change which class SimplePie uses for data sanitization.
1097          * Useful when you are overloading or extending SimplePie's default classes.
1098          *
1099          * @access public
1100          * @param string $class Name of custom class.
1101          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1102          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1103          */
1104         function set_sanitize_class($class = 'SimplePie_Sanitize')
1105         {
1106                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize'))
1107                 {
1108                         $this->sanitize =& new $class;
1109                         return true;
1110                 }
1111                 return false;
1112         }
1113
1114         /**
1115          * Allows you to change which class SimplePie uses for handling feed items.
1116          * Useful when you are overloading or extending SimplePie's default classes.
1117          *
1118          * @access public
1119          * @param string $class Name of custom class.
1120          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1121          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1122          */
1123         function set_item_class($class = 'SimplePie_Item')
1124         {
1125                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item'))
1126                 {
1127                         $this->item_class = $class;
1128                         return true;
1129                 }
1130                 return false;
1131         }
1132
1133         /**
1134          * Allows you to change which class SimplePie uses for handling author data.
1135          * Useful when you are overloading or extending SimplePie's default classes.
1136          *
1137          * @access public
1138          * @param string $class Name of custom class.
1139          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1140          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1141          */
1142         function set_author_class($class = 'SimplePie_Author')
1143         {
1144                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author'))
1145                 {
1146                         $this->author_class = $class;
1147                         return true;
1148                 }
1149                 return false;
1150         }
1151
1152         /**
1153          * Allows you to change which class SimplePie uses for handling category data.
1154          * Useful when you are overloading or extending SimplePie's default classes.
1155          *
1156          * @access public
1157          * @param string $class Name of custom class.
1158          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1159          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1160          */
1161         function set_category_class($class = 'SimplePie_Category')
1162         {
1163                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category'))
1164                 {
1165                         $this->category_class = $class;
1166                         return true;
1167                 }
1168                 return false;
1169         }
1170
1171         /**
1172          * Allows you to change which class SimplePie uses for feed enclosures.
1173          * Useful when you are overloading or extending SimplePie's default classes.
1174          *
1175          * @access public
1176          * @param string $class Name of custom class.
1177          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1178          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1179          */
1180         function set_enclosure_class($class = 'SimplePie_Enclosure')
1181         {
1182                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure'))
1183                 {
1184                         $this->enclosure_class = $class;
1185                         return true;
1186                 }
1187                 return false;
1188         }
1189
1190         /**
1191          * Allows you to change which class SimplePie uses for <media:text> captions
1192          * Useful when you are overloading or extending SimplePie's default classes.
1193          *
1194          * @access public
1195          * @param string $class Name of custom class.
1196          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1197          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1198          */
1199         function set_caption_class($class = 'SimplePie_Caption')
1200         {
1201                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Caption'))
1202                 {
1203                         $this->caption_class = $class;
1204                         return true;
1205                 }
1206                 return false;
1207         }
1208
1209         /**
1210          * Allows you to change which class SimplePie uses for <media:copyright>
1211          * Useful when you are overloading or extending SimplePie's default classes.
1212          *
1213          * @access public
1214          * @param string $class Name of custom class.
1215          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1216          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1217          */
1218         function set_copyright_class($class = 'SimplePie_Copyright')
1219         {
1220                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Copyright'))
1221                 {
1222                         $this->copyright_class = $class;
1223                         return true;
1224                 }
1225                 return false;
1226         }
1227
1228         /**
1229          * Allows you to change which class SimplePie uses for <media:credit>
1230          * Useful when you are overloading or extending SimplePie's default classes.
1231          *
1232          * @access public
1233          * @param string $class Name of custom class.
1234          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1235          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1236          */
1237         function set_credit_class($class = 'SimplePie_Credit')
1238         {
1239                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Credit'))
1240                 {
1241                         $this->credit_class = $class;
1242                         return true;
1243                 }
1244                 return false;
1245         }
1246
1247         /**
1248          * Allows you to change which class SimplePie uses for <media:rating>
1249          * Useful when you are overloading or extending SimplePie's default classes.
1250          *
1251          * @access public
1252          * @param string $class Name of custom class.
1253          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1254          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1255          */
1256         function set_rating_class($class = 'SimplePie_Rating')
1257         {
1258                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Rating'))
1259                 {
1260                         $this->rating_class = $class;
1261                         return true;
1262                 }
1263                 return false;
1264         }
1265
1266         /**
1267          * Allows you to change which class SimplePie uses for <media:restriction>
1268          * Useful when you are overloading or extending SimplePie's default classes.
1269          *
1270          * @access public
1271          * @param string $class Name of custom class.
1272          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1273          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1274          */
1275         function set_restriction_class($class = 'SimplePie_Restriction')
1276         {
1277                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Restriction'))
1278                 {
1279                         $this->restriction_class = $class;
1280                         return true;
1281                 }
1282                 return false;
1283         }
1284
1285         /**
1286          * Allows you to change which class SimplePie uses for content-type sniffing.
1287          * Useful when you are overloading or extending SimplePie's default classes.
1288          *
1289          * @access public
1290          * @param string $class Name of custom class.
1291          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1292          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1293          */
1294         function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1295         {
1296                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer'))
1297                 {
1298                         $this->content_type_sniffer_class = $class;
1299                         return true;
1300                 }
1301                 return false;
1302         }
1303
1304         /**
1305          * Allows you to change which class SimplePie uses item sources.
1306          * Useful when you are overloading or extending SimplePie's default classes.
1307          *
1308          * @access public
1309          * @param string $class Name of custom class.
1310          * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1311          * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1312          */
1313         function set_source_class($class = 'SimplePie_Source')
1314         {
1315                 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source'))
1316                 {
1317                         $this->source_class = $class;
1318                         return true;
1319                 }
1320                 return false;
1321         }
1322
1323         /**
1324          * Allows you to override the default user agent string.
1325          *
1326          * @access public
1327          * @param string $ua New user agent string.
1328          */
1329         function set_useragent($ua = SIMPLEPIE_USERAGENT)
1330         {
1331                 $this->useragent = (string) $ua;
1332         }
1333
1334         /**
1335          * Set callback function to create cache filename with
1336          *
1337          * @access public
1338          * @param mixed $function Callback function
1339          */
1340         function set_cache_name_function($function = 'md5')
1341         {
1342                 if (is_callable($function))
1343                 {
1344                         $this->cache_name_function = $function;
1345                 }
1346         }
1347
1348         /**
1349          * Set javascript query string parameter
1350          *
1351          * @access public
1352          * @param mixed $get Javascript query string parameter
1353          */
1354         function set_javascript($get = 'js')
1355         {
1356                 if ($get)
1357                 {
1358                         $this->javascript = (string) $get;
1359                 }
1360                 else
1361                 {
1362                         $this->javascript = false;
1363                 }
1364         }
1365
1366         /**
1367          * Set options to make SP as fast as possible.  Forgoes a
1368          * substantial amount of data sanitization in favor of speed.
1369          *
1370          * @access public
1371          * @param bool $set Whether to set them or not
1372          */
1373         function set_stupidly_fast($set = false)
1374         {
1375                 if ($set)
1376                 {
1377                         $this->enable_order_by_date(false);
1378                         $this->remove_div(false);
1379                         $this->strip_comments(false);
1380                         $this->strip_htmltags(false);
1381                         $this->strip_attributes(false);
1382                         $this->set_image_handler(false);
1383                 }
1384         }
1385
1386         /**
1387          * Set maximum number of feeds to check with autodiscovery
1388          *
1389          * @access public
1390          * @param int $max Maximum number of feeds to check
1391          */
1392         function set_max_checked_feeds($max = 10)
1393         {
1394                 $this->max_checked_feeds = (int) $max;
1395         }
1396
1397         function remove_div($enable = true)
1398         {
1399                 $this->sanitize->remove_div($enable);
1400         }
1401
1402         function strip_htmltags($tags = '', $encode = null)
1403         {
1404                 if ($tags === '')
1405                 {
1406                         $tags = $this->strip_htmltags;
1407                 }
1408                 $this->sanitize->strip_htmltags($tags);
1409                 if ($encode !== null)
1410                 {
1411                         $this->sanitize->encode_instead_of_strip($tags);
1412                 }
1413         }
1414
1415         function encode_instead_of_strip($enable = true)
1416         {
1417                 $this->sanitize->encode_instead_of_strip($enable);
1418         }
1419
1420         function strip_attributes($attribs = '')
1421         {
1422                 if ($attribs === '')
1423                 {
1424                         $attribs = $this->strip_attributes;
1425                 }
1426                 $this->sanitize->strip_attributes($attribs);
1427         }
1428
1429         function set_output_encoding($encoding = 'UTF-8')
1430         {
1431                 $this->sanitize->set_output_encoding($encoding);
1432         }
1433
1434         function strip_comments($strip = false)
1435         {
1436                 $this->sanitize->strip_comments($strip);
1437         }
1438
1439         /**
1440          * Set element/attribute key/value pairs of HTML attributes
1441          * containing URLs that need to be resolved relative to the feed
1442          *
1443          * @access public
1444          * @since 1.0
1445          * @param array $element_attribute Element/attribute key/value pairs
1446          */
1447         function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
1448         {
1449                 $this->sanitize->set_url_replacements($element_attribute);
1450         }
1451
1452         /**
1453          * Set the handler to enable the display of cached favicons.
1454          *
1455          * @access public
1456          * @param str $page Web-accessible path to the handler_favicon.php file.
1457          * @param str $qs The query string that the value should be passed to.
1458          */
1459         function set_favicon_handler($page = false, $qs = 'i')
1460         {
1461                 if ($page !== false)
1462                 {
1463                         $this->favicon_handler = $page . '?' . $qs . '=';
1464                 }
1465                 else
1466                 {
1467                         $this->favicon_handler = '';
1468                 }
1469         }
1470
1471         /**
1472          * Set the handler to enable the display of cached images.
1473          *
1474          * @access public
1475          * @param str $page Web-accessible path to the handler_image.php file.
1476          * @param str $qs The query string that the value should be passed to.
1477          */
1478         function set_image_handler($page = false, $qs = 'i')
1479         {
1480                 if ($page !== false)
1481                 {
1482                         $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1483                 }
1484                 else
1485                 {
1486                         $this->image_handler = '';
1487                 }
1488         }
1489
1490         /**
1491          * Set the limit for items returned per-feed with multifeeds.
1492          *
1493          * @access public
1494          * @param integer $limit The maximum number of items to return.
1495          */
1496         function set_item_limit($limit = 0)
1497         {
1498                 $this->item_limit = (int) $limit;
1499         }
1500
1501         function init()
1502         {
1503                 // Check absolute bare minimum requirements.
1504                 if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.3.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre'))
1505                 {
1506                         return false;
1507                 }
1508                 // 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.
1509                 elseif (!extension_loaded('xmlreader'))
1510                 {
1511                         static $xml_is_sane = null;
1512                         if ($xml_is_sane === null)
1513                         {
1514                                 $parser_check = xml_parser_create();
1515                                 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1516                                 xml_parser_free($parser_check);
1517                                 $xml_is_sane = isset($values[0]['value']);
1518                         }
1519                         if (!$xml_is_sane)
1520                         {
1521                                 return false;
1522                         }
1523                 }
1524
1525                 if (isset($_GET[$this->javascript]))
1526                 {
1527                         SimplePie_Misc::output_javascript();
1528                         exit;
1529                 }
1530
1531                 // Pass whatever was set with config options over to the sanitizer.
1532                 $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->cache_class);
1533                 $this->sanitize->pass_file_data($this->file_class, $this->timeout, $this->useragent, $this->force_fsockopen);
1534
1535                 if ($this->feed_url !== null || $this->raw_data !== null)
1536                 {
1537                         $this->data = array();
1538                         $this->multifeed_objects = array();
1539                         $cache = false;
1540
1541                         if ($this->feed_url !== null)
1542                         {
1543                                 $parsed_feed_url = SimplePie_Misc::parse_url($this->feed_url);
1544                                 // Decide whether to enable caching
1545                                 if ($this->cache && $parsed_feed_url['scheme'] !== '')
1546                                 {
1547                                         $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc');
1548                                 }
1549                                 // If it's enabled and we don't want an XML dump, use the cache
1550                                 if ($cache && !$this->xml_dump)
1551                                 {
1552                                         // Load the Cache
1553                                         $this->data = $cache->load();
1554                                         if (!empty($this->data))
1555                                         {
1556                                                 // If the cache is for an outdated build of SimplePie
1557                                                 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1558                                                 {
1559                                                         $cache->unlink();
1560                                                         $this->data = array();
1561                                                 }
1562                                                 // If we've hit a collision just rerun it with caching disabled
1563                                                 elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1564                                                 {
1565                                                         $cache = false;
1566                                                         $this->data = array();
1567                                                 }
1568                                                 // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1569                                                 elseif (isset($this->data['feed_url']))
1570                                                 {
1571                                                         // If the autodiscovery cache is still valid use it.
1572                                                         if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1573                                                         {
1574                                                                 // Do not need to do feed autodiscovery yet.
1575                                                                 if ($this->data['feed_url'] === $this->data['url'])
1576                                                                 {
1577                                                                         $cache->unlink();
1578                                                                         $this->data = array();
1579                                                                 }
1580                                                                 else
1581                                                                 {
1582                                                                         $this->set_feed_url($this->data['feed_url']);
1583                                                                         return $this->init();
1584                                                                 }
1585                                                         }
1586                                                 }
1587                                                 // Check if the cache has been updated
1588                                                 elseif ($cache->mtime() + $this->cache_duration < time())
1589                                                 {
1590                                                         // If we have last-modified and/or etag set
1591                                                         if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1592                                                         {
1593                                                                 $headers = array();
1594                                                                 if (isset($this->data['headers']['last-modified']))
1595                                                                 {
1596                                                                         $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1597                                                                 }
1598                                                                 if (isset($this->data['headers']['etag']))
1599                                                                 {
1600                                                                         $headers['if-none-match'] = '"' . $this->data['headers']['etag'] . '"';
1601                                                                 }
1602                                                                 $file =& new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen);
1603                                                                 if ($file->success)
1604                                                                 {
1605                                                                         if ($file->status_code === 304)
1606                                                                         {
1607                                                                                 $cache->touch();
1608                                                                                 return true;
1609                                                                         }
1610                                                                         else
1611                                                                         {
1612                                                                                 $headers = $file->headers;
1613                                                                         }
1614                                                                 }
1615                                                                 else
1616                                                                 {
1617                                                                         unset($file);
1618                                                                 }
1619                                                         }
1620                                                 }
1621                                                 // If the cache is still valid, just return true
1622                                                 else
1623                                                 {
1624                                                         return true;
1625                                                 }
1626                                         }
1627                                         // If the cache is empty, delete it
1628                                         else
1629                                         {
1630                                                 $cache->unlink();
1631                                                 $this->data = array();
1632                                         }
1633                                 }
1634                                 // 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.
1635                                 if (!isset($file))
1636                                 {
1637                                         if (is_a($this->file, 'SimplePie_File') && $this->file->url === $this->feed_url)
1638                                         {
1639                                                 $file =& $this->file;
1640                                         }
1641                                         else
1642                                         {
1643                                                 $file =& new $this->file_class($this->feed_url, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen);
1644                                         }
1645                                 }
1646                                 // If the file connection has an error, set SimplePie::error to that and quit
1647                                 if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1648                                 {
1649                                         $this->error = $file->error;
1650                                         if (!empty($this->data))
1651                                         {
1652                                                 return true;
1653                                         }
1654                                         else
1655                                         {
1656                                                 return false;
1657                                         }
1658                                 }
1659
1660                                 if (!$this->force_feed)
1661                                 {
1662                                         // Check if the supplied URL is a feed, if it isn't, look for it.
1663                                         $locate =& new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class);
1664                                         if (!$locate->is_feed($file))
1665                                         {
1666                                                 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1667                                                 unset($file);
1668                                                 if ($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds))
1669                                                 {
1670                                                         if ($cache)
1671                                                         {
1672                                                                 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1673                                                                 if (!$cache->save($this))
1674                                                                 {
1675                                                                         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);
1676                                                                 }
1677                                                                 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc');
1678                                                         }
1679                                                         $this->feed_url = $file->url;
1680                                                 }
1681                                                 else
1682                                                 {
1683                                                         $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.";
1684                                                         SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1685                                                         return false;
1686                                                 }
1687                                         }
1688                                         $locate = null;
1689                                 }
1690
1691                                 $headers = $file->headers;
1692                                 $data = $file->body;
1693                                 $sniffer =& new $this->content_type_sniffer_class($file);
1694                                 $sniffed = $sniffer->get_type();
1695                         }
1696                         else
1697                         {
1698                                 $data = $this->raw_data;
1699                         }
1700
1701                         // Set up array of possible encodings
1702                         $encodings = array();
1703
1704                         // First check to see if input has been overridden.
1705                         if ($this->input_encoding !== false)
1706                         {
1707                                 $encodings[] = $this->input_encoding;
1708                         }
1709
1710                         $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1711                         $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1712
1713                         // RFC 3023 (only applies to sniffed content)
1714                         if (isset($sniffed))
1715                         {
1716                                 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1717                                 {
1718                                         if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1719                                         {
1720                                                 $encodings[] = strtoupper($charset[1]);
1721                                         }
1722                                         $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
1723                                         $encodings[] = 'UTF-8';
1724                                 }
1725                                 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1726                                 {
1727                                         if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1728                                         {
1729                                                 $encodings[] = $charset[1];
1730                                         }
1731                                         $encodings[] = 'US-ASCII';
1732                                 }
1733                                 // Text MIME-type default
1734                                 elseif (substr($sniffed, 0, 5) === 'text/')
1735                                 {
1736                                         $encodings[] = 'US-ASCII';
1737                                 }
1738                         }
1739
1740                         // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1741                         $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
1742                         $encodings[] = 'UTF-8';
1743                         $encodings[] = 'ISO-8859-1';
1744
1745                         // There's no point in trying an encoding twice
1746                         $encodings = array_unique($encodings);
1747
1748                         // If we want the XML, just output that with the most likely encoding and quit
1749                         if ($this->xml_dump)
1750                         {
1751                                 header('Content-type: text/xml; charset=' . $encodings[0]);
1752                                 echo $data;
1753                                 exit;
1754                         }
1755
1756                         // Loop through each possible encoding, till we return something, or run out of possibilities
1757                         foreach ($encodings as $encoding)
1758                         {
1759                                 // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1760                                 if ($utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8'))
1761                                 {
1762                                         // Create new parser
1763                                         $parser =& new $this->parser_class();
1764
1765                                         // If it's parsed fine
1766                                         if ($parser->parse($utf8_data, 'UTF-8'))
1767                                         {
1768                                                 $this->data = $parser->get_data();
1769                                                 if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE)
1770                                                 {
1771                                                         if (isset($headers))
1772                                                         {
1773                                                                 $this->data['headers'] = $headers;
1774                                                         }
1775                                                         $this->data['build'] = SIMPLEPIE_BUILD;
1776
1777                                                         // Cache the file if caching is enabled
1778                                                         if ($cache && !$cache->save($this))
1779                                                         {
1780                                                                 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);
1781                                                         }
1782                                                         return true;
1783                                                 }
1784                                                 else
1785                                                 {
1786                                                         $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1787                                                         SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1788                                                         return false;
1789                                                 }
1790                                         }
1791                                 }
1792                         }
1793                         if (isset($parser))
1794                         {
1795                                 // We have an error, just set SimplePie_Misc::error to it and quit
1796                                 $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());
1797                         }
1798                         else
1799                         {
1800                                 $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.';
1801                         }
1802                         SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1803                         return false;
1804                 }
1805                 elseif (!empty($this->multifeed_url))
1806                 {
1807                         $i = 0;
1808                         $success = 0;
1809                         $this->multifeed_objects = array();
1810                         foreach ($this->multifeed_url as $url)
1811                         {
1812                                 if (SIMPLEPIE_PHP5)
1813                                 {
1814                                         // This keyword needs to defy coding standards for PHP4 compatibility
1815                                         $this->multifeed_objects[$i] = clone($this);
1816                                 }
1817                                 else
1818                                 {
1819                                         $this->multifeed_objects[$i] = $this;
1820                                 }
1821                                 $this->multifeed_objects[$i]->set_feed_url($url);
1822                                 $success |= $this->multifeed_objects[$i]->init();
1823                                 $i++;
1824                         }
1825                         return (bool) $success;
1826                 }
1827                 else
1828                 {
1829                         return false;
1830                 }
1831         }
1832
1833         /**
1834          * Return the error message for the occured error
1835          *
1836          * @access public
1837          * @return string Error message
1838          */
1839         function error()
1840         {
1841                 return $this->error;
1842         }
1843
1844         function get_encoding()
1845         {
1846                 return $this->sanitize->output_encoding;
1847         }
1848
1849         function handle_content_type($mime = 'text/html')
1850         {
1851                 if (!headers_sent())
1852                 {
1853                         $header = "Content-type: $mime;";
1854                         if ($this->get_encoding())
1855                         {
1856                                 $header .= ' charset=' . $this->get_encoding();
1857                         }
1858                         else
1859                         {
1860                                 $header .= ' charset=UTF-8';
1861                         }
1862                         header($header);
1863                 }
1864         }
1865
1866         function get_type()
1867         {
1868                 if (!isset($this->data['type']))
1869                 {
1870                         $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1871                         if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1872                         {
1873                                 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1874                         }
1875                         elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1876                         {
1877                                 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1878                         }
1879                         elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1880                         {
1881                                 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1882                                 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1883                                 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1884                                 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1885                                 {
1886                                         $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1887                                 }
1888                                 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1889                                 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1890                                 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1891                                 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1892                                 {
1893                                         $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1894                                 }
1895                         }
1896                         elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1897                         {
1898                                 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1899                                 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1900                                 {
1901                                         switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1902                                         {
1903                                                 case '0.91':
1904                                                         $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1905                                                         if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1906                                                         {
1907                                                                 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1908                                                                 {
1909                                                                         case '0':
1910                                                                                 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1911                                                                                 break;
1912
1913                                                                         case '24':
1914                                                                                 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1915                                                                                 break;
1916                                                                 }
1917                                                         }
1918                                                         break;
1919
1920                                                 case '0.92':
1921                                                         $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1922                                                         break;
1923
1924                                                 case '0.93':
1925                                                         $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1926                                                         break;
1927
1928                                                 case '0.94':
1929                                                         $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1930                                                         break;
1931
1932                                                 case '2.0':
1933                                                         $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1934                                                         break;
1935                                         }
1936                                 }
1937                         }
1938                         else
1939                         {
1940                                 $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1941                         }
1942                 }
1943                 return $this->data['type'];
1944         }
1945
1946         /**
1947          * Returns the URL for the favicon of the feed's website.
1948          *
1949          * @todo Cache atom:icon
1950          * @access public
1951          * @since 1.0
1952          */
1953         function get_favicon()
1954         {
1955                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
1956                 {
1957                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1958                 }
1959                 elseif (($url = $this->get_link()) !== null && preg_match('/^http(s)?:\/\//i', $url))
1960                 {
1961                         $favicon = SimplePie_Misc::absolutize_url('/favicon.ico', $url);
1962
1963                         if ($this->cache && $this->favicon_handler)
1964                         {
1965                                 $favicon_filename = call_user_func($this->cache_name_function, $favicon);
1966                                 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $favicon_filename, 'spi');
1967
1968                                 if ($cache->load())
1969                                 {
1970                                         return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
1971                                 }
1972                                 else
1973                                 {
1974                                         $file =& new $this->file_class($favicon, $this->timeout / 10, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
1975
1976                                         if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)) && strlen($file->body) > 0)
1977                                         {
1978                                                 $sniffer =& new $this->content_type_sniffer_class($file);
1979                                                 if (substr($sniffer->get_type(), 0, 6) === 'image/')
1980                                                 {
1981                                                         if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
1982                                                         {
1983                                                                 return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
1984                                                         }
1985                                                         else
1986                                                         {
1987                                                                 trigger_error("$cache->name is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1988                                                                 return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
1989                                                         }
1990                                                 }
1991                                                 // not an image
1992                                                 else
1993                                                 {
1994                                                         return false;
1995                                                 }
1996                                         }
1997                                 }
1998                         }
1999                         else
2000                         {
2001                                 return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
2002                         }
2003                 }
2004                 return false;
2005         }
2006
2007         /**
2008          * @todo If we have a perm redirect we should return the new URL
2009          * @todo When we make the above change, let's support <itunes:new-feed-url> as well
2010          * @todo Also, |atom:link|@rel=self
2011          */
2012         function subscribe_url()
2013         {
2014                 if ($this->feed_url !== null)
2015                 {
2016                         return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
2017                 }
2018                 else
2019                 {
2020                         return null;
2021                 }
2022         }
2023
2024         function subscribe_feed()
2025         {
2026                 if ($this->feed_url !== null)
2027                 {
2028                         return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
2029                 }
2030                 else
2031                 {
2032                         return null;
2033                 }
2034         }
2035
2036         function subscribe_outlook()
2037         {
2038                 if ($this->feed_url !== null)
2039                 {
2040                         return $this->sanitize('outlook' . SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
2041                 }
2042                 else
2043                 {
2044                         return null;
2045                 }
2046         }
2047
2048         function subscribe_podcast()
2049         {
2050                 if ($this->feed_url !== null)
2051                 {
2052                         return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 3), SIMPLEPIE_CONSTRUCT_IRI);
2053                 }
2054                 else
2055                 {
2056                         return null;
2057                 }
2058         }
2059
2060         function subscribe_itunes()
2061         {
2062                 if ($this->feed_url !== null)
2063                 {
2064                         return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 4), SIMPLEPIE_CONSTRUCT_IRI);
2065                 }
2066                 else
2067                 {
2068                         return null;
2069                 }
2070         }
2071
2072         /**
2073          * Creates the subscribe_* methods' return data
2074          *
2075          * @access private
2076          * @param string $feed_url String to prefix to the feed URL
2077          * @param string $site_url String to prefix to the site URL (and
2078          * suffix to the feed URL)
2079          * @return mixed URL if feed exists, false otherwise
2080          */
2081         function subscribe_service($feed_url, $site_url = null)
2082         {
2083                 if ($this->subscribe_url())
2084                 {
2085                         $return = $feed_url . rawurlencode($this->feed_url);
2086                         if ($site_url !== null && $this->get_link() !== null)
2087                         {
2088                                 $return .= $site_url . rawurlencode($this->get_link());
2089                         }
2090                         return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI);
2091                 }
2092                 else
2093                 {
2094                         return null;
2095                 }
2096         }
2097
2098         function subscribe_aol()
2099         {
2100                 return $this->subscribe_service('http://feeds.my.aol.com/add.jsp?url=');
2101         }
2102
2103         function subscribe_bloglines()
2104         {
2105                 return $this->subscribe_service('http://www.bloglines.com/sub/');
2106         }
2107
2108         function subscribe_eskobo()
2109         {
2110                 return $this->subscribe_service('http://www.eskobo.com/?AddToMyPage=');
2111         }
2112
2113         function subscribe_feedfeeds()
2114         {
2115                 return $this->subscribe_service('http://www.feedfeeds.com/add?feed=');
2116         }
2117
2118         function subscribe_feedster()
2119         {
2120                 return $this->subscribe_service('http://www.feedster.com/myfeedster.php?action=addrss&confirm=no&rssurl=');
2121         }
2122
2123         function subscribe_google()
2124         {
2125                 return $this->subscribe_service('http://fusion.google.com/add?feedurl=');
2126         }
2127
2128         function subscribe_gritwire()
2129         {
2130                 return $this->subscribe_service('http://my.gritwire.com/feeds/addExternalFeed.aspx?FeedUrl=');
2131         }
2132
2133         function subscribe_msn()
2134         {
2135                 return $this->subscribe_service('http://my.msn.com/addtomymsn.armx?id=rss&ut=', '&ru=');
2136         }
2137
2138         function subscribe_netvibes()
2139         {
2140                 return $this->subscribe_service('http://www.netvibes.com/subscribe.php?url=');
2141         }
2142
2143         function subscribe_newsburst()
2144         {
2145                 return $this->subscribe_service('http://www.newsburst.com/Source/?add=');
2146         }
2147
2148         function subscribe_newsgator()
2149         {
2150                 return $this->subscribe_service('http://www.newsgator.com/ngs/subscriber/subext.aspx?url=');
2151         }
2152
2153         function subscribe_odeo()
2154         {
2155                 return $this->subscribe_service('http://www.odeo.com/listen/subscribe?feed=');
2156         }
2157
2158         function subscribe_podnova()
2159         {
2160                 return $this->subscribe_service('http://www.podnova.com/index_your_podcasts.srf?action=add&url=');
2161         }
2162
2163         function subscribe_rojo()
2164         {
2165                 return $this->subscribe_service('http://www.rojo.com/add-subscription?resource=');
2166         }
2167
2168         function subscribe_yahoo()
2169         {
2170                 return $this->subscribe_service('http://add.my.yahoo.com/rss?url=');
2171         }
2172
2173         function get_feed_tags($namespace, $tag)
2174         {
2175                 $type = $this->get_type();
2176                 if ($type & SIMPLEPIE_TYPE_ATOM_10)
2177                 {
2178                         if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
2179                         {
2180                                 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
2181                         }
2182                 }
2183                 if ($type & SIMPLEPIE_TYPE_ATOM_03)
2184                 {
2185                         if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
2186                         {
2187                                 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
2188                         }
2189                 }
2190                 if ($type & SIMPLEPIE_TYPE_RSS_RDF)
2191                 {
2192                         if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
2193                         {
2194                                 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
2195                         }
2196                 }
2197                 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2198                 {
2199                         if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
2200                         {
2201                                 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
2202                         }
2203                 }
2204                 return null;
2205         }
2206
2207         function get_channel_tags($namespace, $tag)
2208         {
2209                 $type = $this->get_type();
2210                 if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
2211                 {
2212                         if ($return = $this->get_feed_tags($namespace, $tag))
2213                         {
2214                                 return $return;
2215                         }
2216                 }
2217                 if ($type & SIMPLEPIE_TYPE_RSS_10)
2218                 {
2219                         if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
2220                         {
2221                                 if (isset($channel[0]['child'][$namespace][$tag]))
2222                                 {
2223                                         return $channel[0]['child'][$namespace][$tag];
2224                                 }
2225                         }
2226                 }
2227                 if ($type & SIMPLEPIE_TYPE_RSS_090)
2228                 {
2229                         if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
2230                         {
2231                                 if (isset($channel[0]['child'][$namespace][$tag]))
2232                                 {
2233                                         return $channel[0]['child'][$namespace][$tag];
2234                                 }
2235                         }
2236                 }
2237                 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2238                 {
2239                         if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
2240                         {
2241                                 if (isset($channel[0]['child'][$namespace][$tag]))
2242                                 {
2243                                         return $channel[0]['child'][$namespace][$tag];
2244                                 }
2245                         }
2246                 }
2247                 return null;
2248         }
2249
2250         function get_image_tags($namespace, $tag)
2251         {
2252                 $type = $this->get_type();
2253                 if ($type & SIMPLEPIE_TYPE_RSS_10)
2254                 {
2255                         if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
2256                         {
2257                                 if (isset($image[0]['child'][$namespace][$tag]))
2258                                 {
2259                                         return $image[0]['child'][$namespace][$tag];
2260                                 }
2261                         }
2262                 }
2263                 if ($type & SIMPLEPIE_TYPE_RSS_090)
2264                 {
2265                         if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
2266                         {
2267                                 if (isset($image[0]['child'][$namespace][$tag]))
2268                                 {
2269                                         return $image[0]['child'][$namespace][$tag];
2270                                 }
2271                         }
2272                 }
2273                 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2274                 {
2275                         if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
2276                         {
2277                                 if (isset($image[0]['child'][$namespace][$tag]))
2278                                 {
2279                                         return $image[0]['child'][$namespace][$tag];
2280                                 }
2281                         }
2282                 }
2283                 return null;
2284         }
2285
2286         function get_base($element = array())
2287         {
2288                 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
2289                 {
2290                         return $element['xml_base'];
2291                 }
2292                 elseif ($this->get_link() !== null)
2293                 {
2294                         return $this->get_link();
2295                 }
2296                 else
2297                 {
2298                         return $this->subscribe_url();
2299                 }
2300         }
2301
2302         function sanitize($data, $type, $base = '')
2303         {
2304                 return $this->sanitize->sanitize($data, $type, $base);
2305         }
2306
2307         function get_title()
2308         {
2309                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
2310                 {
2311                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2312                 }
2313                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
2314                 {
2315                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2316                 }
2317                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2318                 {
2319                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2320                 }
2321                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2322                 {
2323                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2324                 }
2325                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2326                 {
2327                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2328                 }
2329                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2330                 {
2331                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2332                 }
2333                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2334                 {
2335                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2336                 }
2337                 else
2338                 {
2339                         return null;
2340                 }
2341         }
2342
2343         function get_category($key = 0)
2344         {
2345                 $categories = $this->get_categories();
2346                 if (isset($categories[$key]))
2347                 {
2348                         return $categories[$key];
2349                 }
2350                 else
2351                 {
2352                         return null;
2353                 }
2354         }
2355
2356         function get_categories()
2357         {
2358                 $categories = array();
2359
2360                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2361                 {
2362                         $term = null;
2363                         $scheme = null;
2364                         $label = null;
2365                         if (isset($category['attribs']['']['term']))
2366                         {
2367                                 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2368                         }
2369                         if (isset($category['attribs']['']['scheme']))
2370                         {
2371                                 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2372                         }
2373                         if (isset($category['attribs']['']['label']))
2374                         {
2375                                 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2376                         }
2377                         $categories[] =& new $this->category_class($term, $scheme, $label);
2378                 }
2379                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2380                 {
2381                         // This is really the label, but keep this as the term also for BC.
2382                         // Label will also work on retrieving because that falls back to term.
2383                         $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2384                         if (isset($category['attribs']['']['domain']))
2385                         {
2386                                 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2387                         }
2388                         else
2389                         {
2390                                 $scheme = null;
2391                         }
2392                         $categories[] =& new $this->category_class($term, $scheme, null);
2393                 }
2394                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2395                 {
2396                         $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2397                 }
2398                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2399                 {
2400                         $categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2401                 }
2402
2403                 if (!empty($categories))
2404                 {
2405                         return SimplePie_Misc::array_unique($categories);
2406                 }
2407                 else
2408                 {
2409                         return null;
2410                 }
2411         }
2412
2413         function get_author($key = 0)
2414         {
2415                 $authors = $this->get_authors();
2416                 if (isset($authors[$key]))
2417                 {
2418                         return $authors[$key];
2419                 }
2420                 else
2421                 {
2422                         return null;
2423                 }
2424         }
2425
2426         function get_authors()
2427         {
2428                 $authors = array();
2429                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2430                 {
2431                         $name = null;
2432                         $uri = null;
2433                         $email = null;
2434                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2435                         {
2436                                 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2437                         }
2438                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2439                         {
2440                                 $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]));
2441                         }
2442                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2443                         {
2444                                 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2445                         }
2446                         if ($name !== null || $email !== null || $uri !== null)
2447                         {
2448                                 $authors[] =& new $this->author_class($name, $uri, $email);
2449                         }
2450                 }
2451                 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2452                 {
2453                         $name = null;
2454                         $url = null;
2455                         $email = null;
2456                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2457                         {
2458                                 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2459                         }
2460                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2461                         {
2462                                 $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]));
2463                         }
2464                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2465                         {
2466                                 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2467                         }
2468                         if ($name !== null || $email !== null || $url !== null)
2469                         {
2470                                 $authors[] =& new $this->author_class($name, $url, $email);
2471                         }
2472                 }
2473                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2474                 {
2475                         $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2476                 }
2477                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2478                 {
2479                         $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2480                 }
2481                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2482                 {
2483                         $authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2484                 }
2485
2486                 if (!empty($authors))
2487                 {
2488                         return SimplePie_Misc::array_unique($authors);
2489                 }
2490                 else
2491                 {
2492                         return null;
2493                 }
2494         }
2495
2496         function get_contributor($key = 0)
2497         {
2498                 $contributors = $this->get_contributors();
2499                 if (isset($contributors[$key]))
2500                 {
2501                         return $contributors[$key];
2502                 }
2503                 else
2504                 {
2505                         return null;
2506                 }
2507         }
2508
2509         function get_contributors()
2510         {
2511                 $contributors = array();
2512                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2513                 {
2514                         $name = null;
2515                         $uri = null;
2516                         $email = null;
2517                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2518                         {
2519                                 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2520                         }
2521                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2522                         {
2523                                 $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]));
2524                         }
2525                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2526                         {
2527                                 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2528                         }
2529                         if ($name !== null || $email !== null || $uri !== null)
2530                         {
2531                                 $contributors[] =& new $this->author_class($name, $uri, $email);
2532                         }
2533                 }
2534                 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2535                 {
2536                         $name = null;
2537                         $url = null;
2538                         $email = null;
2539                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2540                         {
2541                                 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2542                         }
2543                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2544                         {
2545                                 $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]));
2546                         }
2547                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2548                         {
2549                                 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2550                         }
2551                         if ($name !== null || $email !== null || $url !== null)
2552                         {
2553                                 $contributors[] =& new $this->author_class($name, $url, $email);
2554                         }
2555                 }
2556
2557                 if (!empty($contributors))
2558                 {
2559                         return SimplePie_Misc::array_unique($contributors);
2560                 }
2561                 else
2562                 {
2563                         return null;
2564                 }
2565         }
2566
2567         function get_link($key = 0, $rel = 'alternate')
2568         {
2569                 $links = $this->get_links($rel);
2570                 if (isset($links[$key]))
2571                 {
2572                         return $links[$key];
2573                 }
2574                 else
2575                 {
2576                         return null;
2577                 }
2578         }
2579
2580         /**
2581          * Added for parity between the parent-level and the item/entry-level.
2582          */
2583         function get_permalink()
2584         {
2585                 return $this->get_link(0);
2586         }
2587
2588         function get_links($rel = 'alternate')
2589         {
2590                 if (!isset($this->data['links']))
2591                 {
2592                         $this->data['links'] = array();
2593                         if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2594                         {
2595                                 foreach ($links as $link)
2596                                 {
2597                                         if (isset($link['attribs']['']['href']))
2598                                         {
2599                                                 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2600                                                 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2601                                         }
2602                                 }
2603                         }
2604                         if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2605                         {
2606                                 foreach ($links as $link)
2607                                 {
2608                                         if (isset($link['attribs']['']['href']))
2609                                         {
2610                                                 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2611                                                 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2612
2613                                         }
2614                                 }
2615                         }
2616                         if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2617                         {
2618                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2619                         }
2620                         if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2621                         {
2622                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2623                         }
2624                         if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2625                         {
2626                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2627                         }
2628
2629                         $keys = array_keys($this->data['links']);
2630                         foreach ($keys as $key)
2631                         {
2632                                 if (SimplePie_Misc::is_isegment_nz_nc($key))
2633                                 {
2634                                         if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2635                                         {
2636                                                 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2637                                                 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2638                                         }
2639                                         else
2640                                         {
2641                                                 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2642                                         }
2643                                 }
2644                                 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2645                                 {
2646                                         $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2647                                 }
2648                                 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2649                         }
2650                 }
2651
2652                 if (isset($this->data['links'][$rel]))
2653                 {
2654                         return $this->data['links'][$rel];
2655                 }
2656                 else
2657                 {
2658                         return null;
2659                 }
2660         }
2661
2662         function get_all_discovered_feeds()
2663         {
2664                 return $this->all_discovered_feeds;
2665         }
2666
2667         function get_description()
2668         {
2669                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2670                 {
2671                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2672                 }
2673                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2674                 {
2675                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2676                 }
2677                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2678                 {
2679                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2680                 }
2681                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2682                 {
2683                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2684                 }
2685                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2686                 {
2687                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2688                 }
2689                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2690                 {
2691                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2692                 }
2693                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2694                 {
2695                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2696                 }
2697                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2698                 {
2699                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2700                 }
2701                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2702                 {
2703                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2704                 }
2705                 else
2706                 {
2707                         return null;
2708                 }
2709         }
2710
2711         function get_copyright()
2712         {
2713                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2714                 {
2715                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2716                 }
2717                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2718                 {
2719                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2720                 }
2721                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2722                 {
2723                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2724                 }
2725                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2726                 {
2727                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2728                 }
2729                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2730                 {
2731                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2732                 }
2733                 else
2734                 {
2735                         return null;
2736                 }
2737         }
2738
2739         function get_language()
2740         {
2741                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2742                 {
2743                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2744                 }
2745                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2746                 {
2747                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2748                 }
2749                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2750                 {
2751                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2752                 }
2753                 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2754                 {
2755                         return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2756                 }
2757                 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2758                 {
2759                         return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2760                 }
2761                 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2762                 {
2763                         return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2764                 }
2765                 elseif (isset($this->data['headers']['content-language']))
2766                 {
2767                         return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2768                 }
2769                 else
2770                 {
2771                         return null;
2772                 }
2773         }
2774
2775         function get_latitude()
2776         {
2777                 
2778                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2779                 {
2780                         return (float) $return[0]['data'];
2781                 }
2782                 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))
2783                 {
2784                         return (float) $match[1];
2785                 }
2786                 else
2787                 {
2788                         return null;
2789                 }
2790         }
2791
2792         function get_longitude()
2793         {
2794                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2795                 {
2796                         return (float) $return[0]['data'];
2797                 }
2798                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2799                 {
2800                         return (float) $return[0]['data'];
2801                 }
2802                 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))
2803                 {
2804                         return (float) $match[2];
2805                 }
2806                 else
2807                 {
2808                         return null;
2809                 }
2810         }
2811
2812         function get_image_title()
2813         {
2814                 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2815                 {
2816                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2817                 }
2818                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2819                 {
2820                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2821                 }
2822                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2823                 {
2824                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2825                 }
2826                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2827                 {
2828                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2829                 }
2830                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2831                 {
2832                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2833                 }
2834                 else
2835                 {
2836                         return null;
2837                 }
2838         }
2839
2840         function get_image_url()
2841         {
2842                 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2843                 {
2844                         return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2845                 }
2846                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2847                 {
2848                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2849                 }
2850                 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2851                 {
2852                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2853                 }
2854                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2855                 {
2856                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2857                 }
2858                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2859                 {
2860                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2861                 }
2862                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2863                 {
2864                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2865                 }
2866                 else
2867                 {
2868                         return null;
2869                 }
2870         }
2871
2872         function get_image_link()
2873         {
2874                 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2875                 {
2876                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2877                 }
2878                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2879                 {
2880                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2881                 }
2882                 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2883                 {
2884                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2885                 }
2886                 else
2887                 {
2888                         return null;
2889                 }
2890         }
2891
2892         function get_image_width()
2893         {
2894                 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2895                 {
2896                         return round($return[0]['data']);
2897                 }
2898                 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2899                 {
2900                         return 88.0;
2901                 }
2902                 else
2903                 {
2904                         return null;
2905                 }
2906         }
2907
2908         function get_image_height()
2909         {
2910                 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2911                 {
2912                         return round($return[0]['data']);
2913                 }
2914                 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2915                 {
2916                         return 31.0;
2917                 }
2918                 else
2919                 {
2920                         return null;
2921                 }
2922         }
2923
2924         function get_item_quantity($max = 0)
2925         {
2926                 $max = (int) $max;
2927                 $qty = count($this->get_items());
2928                 if ($max === 0)
2929                 {
2930                         return $qty;
2931                 }
2932                 else
2933                 {
2934                         return ($qty > $max) ? $max : $qty;
2935                 }
2936         }
2937
2938         function get_item($key = 0)
2939         {
2940                 $items = $this->get_items();
2941                 if (isset($items[$key]))
2942                 {
2943                         return $items[$key];
2944                 }
2945                 else
2946                 {
2947                         return null;
2948                 }
2949         }
2950
2951         function get_items($start = 0, $end = 0)
2952         {
2953                 if (!isset($this->data['items']))
2954                 {
2955                         if (!empty($this->multifeed_objects))
2956                         {
2957                                 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
2958                         }
2959                         else
2960                         {
2961                                 $this->data['items'] = array();
2962                                 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
2963                                 {
2964                                         $keys = array_keys($items);
2965                                         foreach ($keys as $key)
2966                                         {
2967                                                 $this->data['items'][] =& new $this->item_class($this, $items[$key]);
2968                                         }
2969                                 }
2970                                 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
2971                                 {
2972                                         $keys = array_keys($items);
2973                                         foreach ($keys as $key)
2974                                         {
2975                                                 $this->data['items'][] =& new $this->item_class($this, $items[$key]);
2976                                         }
2977                                 }
2978                                 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
2979                                 {
2980                                         $keys = array_keys($items);
2981                                         foreach ($keys as $key)
2982                                         {
2983                                                 $this->data['items'][] =& new $this->item_class($this, $items[$key]);
2984                                         }
2985                                 }
2986                                 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2987                                 {
2988                                         $keys = array_keys($items);
2989                                         foreach ($keys as $key)
2990                                         {
2991                                                 $this->data['items'][] =& new $this->item_class($this, $items[$key]);
2992                                         }
2993                                 }
2994                                 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
2995                                 {
2996                                         $keys = array_keys($items);
2997                                         foreach ($keys as $key)
2998                                         {
2999                                                 $this->data['items'][] =& new $this->item_class($this, $items[$key]);
3000                                         }
3001                                 }
3002                         }
3003                 }
3004
3005                 if (!empty($this->data['items']))
3006                 {
3007                         // If we want to order it by date, check if all items have a date, and then sort it
3008                         if ($this->order_by_date && empty($this->multifeed_objects))
3009                         {
3010                                 if (!isset($this->data['ordered_items']))
3011                                 {
3012                                         $do_sort = true;
3013                                         foreach ($this->data['items'] as $item)
3014                                         {
3015                                                 if (!$item->get_date('U'))
3016                                                 {
3017                                                         $do_sort = false;
3018                                                         break;
3019                                                 }
3020                                         }
3021                                         $item = null;
3022                                         $this->data['ordered_items'] = $this->data['items'];
3023                                         if ($do_sort)
3024                                         {
3025                                                 usort($this->data['ordered_items'], array(&$this, 'sort_items'));
3026                                         }
3027                                 }
3028                                 $items = $this->data['ordered_items'];
3029                         }
3030                         else
3031                         {
3032                                 $items = $this->data['items'];
3033                         }
3034
3035                         // Slice the data as desired
3036                         if ($end === 0)
3037                         {
3038                                 return array_slice($items, $start);
3039                         }
3040                         else
3041                         {
3042                                 return array_slice($items, $start, $end);
3043                         }
3044                 }
3045                 else
3046                 {
3047                         return array();
3048                 }
3049         }
3050
3051         /**
3052          * @static
3053          */
3054         function sort_items($a, $b)
3055         {
3056                 return $a->get_date('U') <= $b->get_date('U');
3057         }
3058
3059         /**
3060          * @static
3061          */
3062         function merge_items($urls, $start = 0, $end = 0, $limit = 0)
3063         {
3064                 if (is_array($urls) && sizeof($urls) > 0)
3065                 {
3066                         $items = array();
3067                         foreach ($urls as $arg)
3068                         {
3069                                 if (is_a($arg, 'SimplePie'))
3070                                 {
3071                                         $items = array_merge($items, $arg->get_items(0, $limit));
3072                                 }
3073                                 else
3074                                 {
3075                                         trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
3076                                 }
3077                         }
3078
3079                         $do_sort = true;
3080                         foreach ($items as $item)
3081                         {
3082                                 if (!$item->get_date('U'))
3083                                 {
3084                                         $do_sort = false;
3085                                         break;
3086                                 }
3087                         }
3088                         $item = null;
3089                         if ($do_sort)
3090                         {
3091                                 usort($items, array('SimplePie', 'sort_items'));
3092                         }
3093
3094                         if ($end === 0)
3095                         {
3096                                 return array_slice($items, $start);
3097                         }
3098                         else
3099                         {
3100                                 return array_slice($items, $start, $end);
3101                         }
3102                 }
3103                 else
3104                 {
3105                         trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
3106                         return array();
3107                 }
3108         }
3109 }
3110
3111 class SimplePie_Item
3112 {
3113         var $feed;
3114         var $data = array();
3115
3116         function SimplePie_Item($feed, $data)
3117         {
3118                 $this->feed = $feed;
3119                 $this->data = $data;
3120         }
3121
3122         function __toString()
3123         {
3124                 return md5(serialize($this->data));
3125         }
3126
3127         /**
3128          * Remove items that link back to this before destroying this object
3129          */
3130         function __destruct()
3131         {
3132                 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
3133                 {
3134                         unset($this->feed);
3135                 }
3136         }
3137
3138         function get_item_tags($namespace, $tag)
3139         {
3140                 if (isset($this->data['child'][$namespace][$tag]))
3141                 {
3142                         return $this->data['child'][$namespace][$tag];
3143                 }
3144                 else
3145                 {
3146                         return null;
3147                 }
3148         }
3149
3150         function get_base($element = array())
3151         {
3152                 return $this->feed->get_base($element);
3153         }
3154
3155         function sanitize($data, $type, $base = '')
3156         {
3157                 return $this->feed->sanitize($data, $type, $base);
3158         }
3159
3160         function get_feed()
3161         {
3162                 return $this->feed;
3163         }
3164
3165         function get_id($hash = false)
3166         {
3167                 if (!$hash)
3168                 {
3169                         if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
3170                         {
3171                                 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3172                         }
3173                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
3174                         {
3175                                 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3176                         }
3177                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
3178                         {
3179                                 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3180                         }
3181                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
3182                         {
3183                                 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3184                         }
3185                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
3186                         {
3187                                 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3188                         }
3189                         elseif (($return = $this->get_permalink()) !== null)
3190                         {
3191                                 return $return;
3192                         }
3193                         elseif (($return = $this->get_title()) !== null)
3194                         {
3195                                 return $return;
3196                         }
3197                 }
3198                 if ($this->get_permalink() !== null || $this->get_title() !== null)
3199                 {
3200                         return md5($this->get_permalink() . $this->get_title());
3201                 }
3202                 else
3203                 {
3204                         return md5(serialize($this->data));
3205                 }
3206         }
3207
3208         function get_title()
3209         {
3210                 if (!isset($this->data['title']))
3211                 {
3212                         if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
3213                         {
3214                                 $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3215                         }
3216                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
3217                         {
3218                                 $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3219                         }
3220                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
3221                         {
3222                                 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3223                         }
3224                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
3225                         {
3226                                 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3227                         }
3228                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
3229                         {
3230                                 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3231                         }
3232                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
3233                         {
3234                                 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3235                         }
3236                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
3237                         {
3238                                 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3239                         }
3240                         else
3241                         {
3242                                 $this->data['title'] = null;
3243                         }
3244                 }
3245                 return $this->data['title'];
3246         }
3247
3248         function get_description($description_only = false)
3249         {
3250                 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
3251                 {
3252                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3253                 }
3254                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
3255                 {
3256                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3257                 }
3258                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
3259                 {
3260                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3261                 }
3262                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
3263                 {
3264                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
3265                 }
3266                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
3267                 {
3268                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3269                 }
3270                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
3271                 {
3272                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3273                 }
3274                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
3275                 {
3276                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
3277                 }
3278                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
3279                 {
3280                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3281                 }
3282                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
3283                 {
3284                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
3285                 }
3286
3287                 elseif (!$description_only)
3288                 {
3289                         return $this->get_content(true);
3290                 }
3291                 else
3292                 {
3293                         return null;
3294                 }
3295         }
3296
3297         function get_content($content_only = false)
3298         {
3299                 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
3300                 {
3301                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_content_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3302                 }
3303                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
3304                 {
3305                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3306                 }
3307                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
3308                 {
3309                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
3310                 }
3311                 elseif (!$content_only)
3312                 {
3313                         return $this->get_description(true);
3314                 }
3315                 else
3316                 {
3317                         return null;
3318                 }
3319         }
3320
3321         function get_category($key = 0)
3322         {
3323                 $categories = $this->get_categories();
3324                 if (isset($categories[$key]))
3325                 {
3326                         return $categories[$key];
3327                 }
3328                 else
3329                 {
3330                         return null;
3331                 }
3332         }
3333
3334         function get_categories()
3335         {
3336                 $categories = array();
3337
3338                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
3339                 {
3340                         $term = null;
3341                         $scheme = null;
3342                         $label = null;
3343                         if (isset($category['attribs']['']['term']))
3344                         {
3345                                 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
3346                         }
3347                         if (isset($category['attribs']['']['scheme']))
3348                         {
3349                                 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
3350                         }
3351                         if (isset($category['attribs']['']['label']))
3352                         {
3353                                 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
3354                         }
3355                         $categories[] =& new $this->feed->category_class($term, $scheme, $label);
3356                 }
3357                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
3358                 {
3359                         // This is really the label, but keep this as the term also for BC.
3360                         // Label will also work on retrieving because that falls back to term.
3361                         $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3362                         if (isset($category['attribs']['']['domain']))
3363                         {
3364                                 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
3365                         }
3366                         else
3367                         {
3368                                 $scheme = null;
3369                         }
3370                         $categories[] =& new $this->feed->category_class($term, $scheme, null);
3371                 }
3372                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
3373                 {
3374                         $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3375                 }
3376                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
3377                 {
3378                         $categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3379                 }
3380
3381                 if (!empty($categories))
3382                 {
3383                         return SimplePie_Misc::array_unique($categories);
3384                 }
3385                 else
3386                 {
3387                         return null;
3388                 }
3389         }
3390
3391         function get_author($key = 0)
3392         {
3393                 $authors = $this->get_authors();
3394                 if (isset($authors[$key]))
3395                 {
3396                         return $authors[$key];
3397                 }
3398                 else
3399                 {
3400                         return null;
3401                 }
3402         }
3403
3404         function get_contributor($key = 0)
3405         {
3406                 $contributors = $this->get_contributors();
3407                 if (isset($contributors[$key]))
3408                 {
3409                         return $contributors[$key];
3410                 }
3411                 else
3412                 {
3413                         return null;
3414                 }
3415         }
3416
3417         function get_contributors()
3418         {
3419                 $contributors = array();
3420                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
3421                 {
3422                         $name = null;
3423                         $uri = null;
3424                         $email = null;
3425                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
3426                         {
3427                                 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3428                         }
3429                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
3430                         {
3431                                 $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]));
3432                         }
3433                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
3434                         {
3435                                 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3436                         }
3437                         if ($name !== null || $email !== null || $uri !== null)
3438                         {
3439                                 $contributors[] =& new $this->feed->author_class($name, $uri, $email);
3440                         }
3441                 }
3442                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
3443                 {
3444                         $name = null;
3445                         $url = null;
3446                         $email = null;
3447                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
3448                         {
3449                                 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3450                         }
3451                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
3452                         {
3453                                 $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]));
3454                         }
3455                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
3456                         {
3457                                 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3458                         }
3459                         if ($name !== null || $email !== null || $url !== null)
3460                         {
3461                                 $contributors[] =& new $this->feed->author_class($name, $url, $email);
3462                         }
3463                 }
3464
3465                 if (!empty($contributors))
3466                 {
3467                         return SimplePie_Misc::array_unique($contributors);
3468                 }
3469                 else
3470                 {
3471                         return null;
3472                 }
3473         }
3474
3475         function get_authors()
3476         {
3477                 $authors = array();
3478                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
3479                 {
3480                         $name = null;
3481                         $uri = null;
3482                         $email = null;
3483                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
3484                         {
3485                                 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3486                         }
3487                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
3488                         {
3489                                 $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]));
3490                         }
3491                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
3492                         {
3493                                 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3494                         }
3495                         if ($name !== null || $email !== null || $uri !== null)
3496                         {
3497                                 $authors[] =& new $this->feed->author_class($name, $uri, $email);
3498                         }
3499                 }
3500                 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
3501                 {
3502                         $name = null;
3503                         $url = null;
3504                         $email = null;
3505                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
3506                         {
3507                                 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3508                         }
3509                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
3510                         {
3511                                 $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]));
3512                         }
3513                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
3514                         {
3515                                 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3516                         }
3517                         if ($name !== null || $email !== null || $url !== null)
3518                         {
3519                                 $authors[] =& new $this->feed->author_class($name, $url, $email);
3520                         }
3521                 }
3522                 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
3523                 {
3524                         $authors[] =& new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
3525                 }
3526                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
3527                 {
3528                         $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3529                 }
3530                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
3531                 {
3532                         $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3533                 }
3534                 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
3535                 {
3536                         $authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3537                 }
3538
3539                 if (!empty($authors))
3540                 {
3541                         return SimplePie_Misc::array_unique($authors);
3542                 }
3543                 elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
3544                 {
3545                         return $authors;
3546                 }
3547                 elseif ($authors = $this->feed->get_authors())
3548                 {
3549                         return $authors;
3550                 }
3551                 else
3552                 {
3553                         return null;
3554                 }
3555         }
3556
3557         function get_copyright()
3558         {
3559                 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
3560                 {
3561                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3562                 }
3563                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
3564                 {
3565                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3566                 }
3567                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
3568                 {
3569                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3570                 }
3571                 else
3572                 {
3573                         return null;
3574                 }
3575         }
3576
3577         function get_date($date_format = 'j F Y, g:i a')
3578         {
3579                 if (!isset($this->data['date']))
3580                 {
3581                         if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
3582                         {
3583                                 $this->data['date']['raw'] = $return[0]['data'];
3584                         }
3585                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
3586                         {
3587                                 $this->data['date']['raw'] = $return[0]['data'];
3588                         }
3589                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
3590                         {
3591                                 $this->data['date']['raw'] = $return[0]['data'];
3592                         }
3593                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
3594                         {
3595                                 $this->data['date']['raw'] = $return[0]['data'];
3596                         }
3597                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
3598                         {
3599                                 $this->data['date']['raw'] = $return[0]['data'];
3600                         }
3601                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
3602                         {
3603                                 $this->data['date']['raw'] = $return[0]['data'];
3604                         }
3605                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
3606                         {
3607                                 $this->data['date']['raw'] = $return[0]['data'];
3608                         }
3609                         elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
3610                         {
3611                                 $this->data['date']['raw'] = $return[0]['data'];
3612                         }
3613
3614                         if (!empty($this->data['date']['raw']))
3615                         {
3616                                 $parser = SimplePie_Parse_Date::get();
3617                                 $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
3618                         }
3619                         else
3620                         {
3621                                 $this->data['date'] = null;
3622                         }
3623                 }
3624                 if ($this->data['date'])
3625                 {
3626                         $date_format = (string) $date_format;
3627                         switch ($date_format)
3628                         {
3629                                 case '':
3630                                         return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
3631
3632                                 case 'U':
3633                                         return $this->data['date']['parsed'];
3634
3635                                 default:
3636                                         return date($date_format, $this->data['date']['parsed']);
3637                         }
3638                 }
3639                 else
3640                 {
3641                         return null;
3642                 }
3643         }
3644
3645         function get_local_date($date_format = '%c')
3646         {
3647                 if (!$date_format)
3648                 {
3649                         return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
3650                 }
3651                 elseif (($date = $this->get_date('U')) !== null && $date !== false)
3652                 {
3653                         return strftime($date_format, $date);
3654                 }
3655                 else
3656                 {
3657                         return null;
3658                 }
3659         }
3660
3661         function get_permalink()
3662         {
3663                 $link = $this->get_link();
3664                 $enclosure = $this->get_enclosure(0);
3665                 if ($link !== null)
3666                 {
3667                         return $link;
3668                 }
3669                 elseif ($enclosure !== null)
3670                 {
3671                         return $enclosure->get_link();
3672                 }
3673                 else
3674                 {
3675                         return null;
3676                 }
3677         }
3678
3679         function get_link($key = 0, $rel = 'alternate')
3680         {
3681                 $links = $this->get_links($rel);
3682                 if ($links[$key] !== null)
3683                 {
3684                         return $links[$key];
3685                 }
3686                 else
3687                 {
3688                         return null;
3689                 }
3690         }
3691
3692         function get_links($rel = 'alternate')
3693         {
3694                 if (!isset($this->data['links']))
3695                 {
3696                         $this->data['links'] = array();
3697                         foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
3698                         {
3699                                 if (isset($link['attribs']['']['href']))
3700                                 {
3701                                         $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
3702                                         $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
3703
3704                                 }
3705                         }
3706                         foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
3707                         {
3708                                 if (isset($link['attribs']['']['href']))
3709                                 {
3710                                         $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
3711                                         $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
3712                                 }
3713                         }
3714                         if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
3715                         {
3716                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3717                         }
3718                         if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
3719                         {
3720                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3721                         }
3722                         if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
3723                         {
3724                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3725                         }
3726                         if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
3727                         {
3728                                 if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
3729                                 {
3730                                         $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3731                                 }
3732                         }
3733
3734                         $keys = array_keys($this->data['links']);
3735                         foreach ($keys as $key)
3736                         {
3737                                 if (SimplePie_Misc::is_isegment_nz_nc($key))
3738                                 {
3739                                         if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
3740                                         {
3741                                                 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
3742                                                 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
3743                                         }
3744                                         else
3745                                         {
3746                                                 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
3747                                         }
3748                                 }
3749                                 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
3750                                 {
3751                                         $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
3752                                 }
3753                                 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
3754                         }
3755                 }
3756                 if (isset($this->data['links'][$rel]))
3757                 {
3758                         return $this->data['links'][$rel];
3759                 }
3760                 else
3761                 {
3762                         return null;
3763                 }
3764         }
3765
3766         /**
3767          * @todo Add ability to prefer one type of content over another (in a media group).
3768          */
3769         function get_enclosure($key = 0, $prefer = null)
3770         {
3771                 $enclosures = $this->get_enclosures();
3772                 if (isset($enclosures[$key]))
3773                 {
3774                         return $enclosures[$key];
3775                 }
3776                 else
3777                 {
3778                         return null;
3779                 }
3780         }
3781
3782         /**
3783          * Grabs all available enclosures (podcasts, etc.)
3784          *
3785          * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
3786          *
3787          * At this point, we're pretty much assuming that all enclosures for an item are the same content.  Anything else is too complicated to properly support.
3788          *
3789          * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
3790          * @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).
3791          */
3792         function get_enclosures()
3793         {
3794                 if (!isset($this->data['enclosures']))
3795                 {
3796                         $this->data['enclosures'] = array();
3797
3798                         // Elements
3799                         $captions_parent = null;
3800                         $categories_parent = null;
3801                         $copyrights_parent = null;
3802                         $credits_parent = null;
3803                         $description_parent = null;
3804                         $duration_parent = null;
3805                         $hashes_parent = null;
3806                         $keywords_parent = null;
3807                         $player_parent = null;
3808                         $ratings_parent = null;
3809                         $restrictions_parent = null;
3810                         $thumbnails_parent = null;
3811                         $title_parent = null;
3812
3813                         // Let's do the channel and item-level ones first, and just re-use them if we need to.
3814                         $parent = $this->get_feed();
3815
3816                         // CAPTIONS
3817                         if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
3818                         {
3819                                 foreach ($captions as $caption)
3820                                 {
3821                                         $caption_type = null;
3822                                         $caption_lang = null;
3823                                         $caption_startTime = null;
3824                                         $caption_endTime = null;
3825                                         $caption_text = null;
3826                                         if (isset($caption['attribs']['']['type']))
3827                                         {
3828                                                 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
3829                                         }
3830                                         if (isset($caption['attribs']['']['lang']))
3831                                         {
3832                                                 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
3833                                         }
3834                                         if (isset($caption['attribs']['']['start']))
3835                                         {
3836                                                 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
3837                                         }
3838                                         if (isset($caption['attribs']['']['end']))
3839                                         {
3840                                                 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
3841                                         }
3842                                         if (isset($caption['data']))
3843                                         {
3844                                                 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3845                                         }
3846                                         $captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
3847                                 }
3848                         }
3849                         elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
3850                         {
3851                                 foreach ($captions as $caption)
3852                                 {
3853                                         $caption_type = null;
3854                                         $caption_lang = null;
3855                                         $caption_startTime = null;
3856                                         $caption_endTime = null;
3857                                         $caption_text = null;
3858                                         if (isset($caption['attribs']['']['type']))
3859                                         {
3860                                                 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
3861                                         }
3862                                         if (isset($caption['attribs']['']['lang']))
3863                                         {
3864                                                 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
3865                                         }
3866                                         if (isset($caption['attribs']['']['start']))
3867                                         {
3868                                                 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
3869                                         }
3870                                         if (isset($caption['attribs']['']['end']))
3871                                         {
3872                                                 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
3873                                         }
3874                                         if (isset($caption['data']))
3875                                         {
3876                                                 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3877                                         }
3878                                         $captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
3879                                 }
3880                         }
3881                         if (is_array($captions_parent))
3882                         {
3883                                 $captions_parent = array_values(SimplePie_Misc::array_unique($captions_parent));
3884                         }
3885
3886                         // CATEGORIES
3887                         foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
3888                         {
3889                                 $term = null;
3890                                 $scheme = null;
3891                                 $label = null;
3892                                 if (isset($category['data']))
3893                                 {
3894                                         $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3895                                 }
3896                                 if (isset($category['attribs']['']['scheme']))
3897                                 {
3898                                         $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
3899                                 }
3900                                 else
3901                                 {
3902                                         $scheme = 'http://search.yahoo.com/mrss/category_schema';
3903                                 }
3904                                 if (isset($category['attribs']['']['label']))
3905                                 {
3906                                         $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
3907                                 }
3908                                 $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
3909                         }
3910                         foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
3911                         {
3912                                 $term = null;
3913                                 $scheme = null;
3914                                 $label = null;
3915                                 if (isset($category['data']))
3916                                 {
3917                                         $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3918                                 }
3919                                 if (isset($category['attribs']['']['scheme']))
3920                                 {
3921                                         $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
3922                                 }
3923                                 else
3924                                 {
3925                                         $scheme = 'http://search.yahoo.com/mrss/category_schema';
3926                                 }
3927                                 if (isset($category['attribs']['']['label']))
3928                                 {
3929                                         $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
3930                                 }
3931                                 $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
3932                         }
3933                         foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
3934                         {
3935                                 $term = null;
3936                                 $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
3937                                 $label = null;
3938                                 if (isset($category['attribs']['']['text']))
3939                                 {
3940                                         $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
3941                                 }
3942                                 $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
3943
3944                                 if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
3945                                 {
3946                                         foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
3947                                         {
3948                                                 if (isset($subcategory['attribs']['']['text']))
3949                                                 {
3950                                                         $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
3951                                                 }
3952                                                 $categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
3953                                         }
3954                                 }
3955                         }
3956                         if (is_array($categories_parent))
3957                         {
3958                                 $categories_parent = array_values(SimplePie_Misc::array_unique($categories_parent));
3959                         }
3960
3961                         // COPYRIGHT
3962                         if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
3963                         {
3964                                 $copyright_url = null;
3965                                 $copyright_label = null;
3966                                 if (isset($copyright[0]['attribs']['']['url']))
3967                                 {
3968                                         $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
3969                                 }
3970                                 if (isset($copyright[0]['data']))
3971                                 {
3972                                         $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3973                                 }
3974                                 $copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label);
3975                         }
3976                         elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
3977                         {
3978                                 $copyright_url = null;
3979                                 $copyright_label = null;
3980                                 if (isset($copyright[0]['attribs']['']['url']))
3981                                 {
3982                                         $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
3983                                 }
3984                                 if (isset($copyright[0]['data']))
3985                                 {
3986                                         $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3987                                 }
3988                                 $copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label);
3989                         }
3990
3991                         // CREDITS
3992                         if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
3993                         {
3994                                 foreach ($credits as $credit)
3995                                 {
3996                                         $credit_role = null;
3997                                         $credit_scheme = null;
3998                                         $credit_name = null;
3999                                         if (isset($credit['attribs']['']['role']))
4000                                         {
4001                                                 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4002                                         }
4003                                         if (isset($credit['attribs']['']['scheme']))
4004                                         {
4005                                                 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4006                                         }
4007                                         else
4008                                         {
4009                                                 $credit_scheme = 'urn:ebu';
4010                                         }
4011                                         if (isset($credit['data']))
4012                                         {
4013                                                 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4014                                         }
4015                                         $credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4016                                 }
4017                         }
4018                         elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
4019                         {
4020                                 foreach ($credits as $credit)
4021                                 {
4022                                         $credit_role = null;
4023                                         $credit_scheme = null;
4024                                         $credit_name = null;
4025                                         if (isset($credit['attribs']['']['role']))
4026                                         {
4027                                                 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4028                                         }
4029                                         if (isset($credit['attribs']['']['scheme']))
4030                                         {
4031                                                 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4032                                         }
4033                                         else
4034                                         {
4035                                                 $credit_scheme = 'urn:ebu';
4036                                         }
4037                                         if (isset($credit['data']))
4038                                         {
4039                                                 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4040                                         }
4041                                         $credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4042                                 }
4043                         }
4044                         if (is_array($credits_parent))
4045                         {
4046                                 $credits_parent = array_values(SimplePie_Misc::array_unique($credits_parent));
4047                         }
4048
4049                         // DESCRIPTION
4050                         if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
4051                         {
4052                                 if (isset($description_parent[0]['data']))
4053                                 {
4054                                         $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4055                                 }
4056                         }
4057                         elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
4058                         {
4059                                 if (isset($description_parent[0]['data']))
4060                                 {
4061                                         $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4062                                 }
4063                         }
4064
4065                         // DURATION
4066                         if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
4067                         {
4068                                 $seconds = null;
4069                                 $minutes = null;
4070                                 $hours = null;
4071                                 if (isset($duration_parent[0]['data']))
4072                                 {
4073                                         $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4074                                         if (sizeof($temp) > 0)
4075                                         {
4076                                                 $seconds = (int) array_pop($temp);
4077                                         }
4078                                         if (sizeof($temp) > 0)
4079                                         {
4080                                                 $minutes = (int) array_pop($temp);
4081                                                 $seconds += $minutes * 60;
4082                                         }
4083                                         if (sizeof($temp) > 0)
4084                                         {
4085                                                 $hours = (int) array_pop($temp);
4086                                                 $seconds += $hours * 3600;
4087                                         }
4088                                         unset($temp);
4089                                         $duration_parent = $seconds;
4090                                 }
4091                         }
4092
4093                         // HASHES
4094                         if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
4095                         {
4096                                 foreach ($hashes_iterator as $hash)
4097                                 {
4098                                         $value = null;
4099                                         $algo = null;
4100                                         if (isset($hash['data']))
4101                                         {
4102                                                 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4103                                         }
4104                                         if (isset($hash['attribs']['']['algo']))
4105                                         {
4106                                                 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4107                                         }
4108                                         else
4109                                         {
4110                                                 $algo = 'md5';
4111                                         }
4112                                         $hashes_parent[] = $algo.':'.$value;
4113                                 }
4114                         }
4115                         elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
4116                         {
4117                                 foreach ($hashes_iterator as $hash)
4118                                 {
4119                                         $value = null;
4120                                         $algo = null;
4121                                         if (isset($hash['data']))
4122                                         {
4123                                                 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4124                                         }
4125                                         if (isset($hash['attribs']['']['algo']))
4126                                         {
4127                                                 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4128                                         }
4129                                         else
4130                                         {
4131                                                 $algo = 'md5';
4132                                         }
4133                                         $hashes_parent[] = $algo.':'.$value;
4134                                 }
4135                         }
4136                         if (is_array($hashes_parent))
4137                         {
4138                                 $hashes_parent = array_values(SimplePie_Misc::array_unique($hashes_parent));
4139                         }
4140
4141                         // KEYWORDS
4142                         if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
4143                         {
4144                                 if (isset($keywords[0]['data']))
4145                                 {
4146                                         $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4147                                         foreach ($temp as $word)
4148                                         {
4149                                                 $keywords_parent[] = trim($word);
4150                                         }
4151                                 }
4152                                 unset($temp);
4153                         }
4154                         elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
4155                         {
4156                                 if (isset($keywords[0]['data']))
4157                                 {
4158                                         $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4159                                         foreach ($temp as $word)
4160                                         {
4161                                                 $keywords_parent[] = trim($word);
4162                                         }
4163                                 }
4164                                 unset($temp);
4165                         }
4166                         elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
4167                         {
4168                                 if (isset($keywords[0]['data']))
4169                                 {
4170                                         $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4171                                         foreach ($temp as $word)
4172                                         {
4173                                                 $keywords_parent[] = trim($word);
4174                                         }
4175                                 }
4176                                 unset($temp);
4177                         }
4178                         elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
4179                         {
4180                                 if (isset($keywords[0]['data']))
4181                                 {
4182                                         $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4183                                         foreach ($temp as $word)
4184                                         {
4185                                                 $keywords_parent[] = trim($word);
4186                                         }
4187                                 }
4188                                 unset($temp);
4189                         }
4190                         if (is_array($keywords_parent))
4191                         {
4192                                 $keywords_parent = array_values(SimplePie_Misc::array_unique($keywords_parent));
4193                         }
4194
4195                         // PLAYER
4196                         if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
4197                         {
4198                                 if (isset($player_parent[0]['attribs']['']['url']))
4199                                 {
4200                                         $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4201                                 }
4202                         }
4203                         elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
4204                         {
4205                                 if (isset($player_parent[0]['attribs']['']['url']))
4206                                 {
4207                                         $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4208                                 }
4209                         }
4210
4211                         // RATINGS
4212                         if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
4213                         {
4214                                 foreach ($ratings as $rating)
4215                                 {
4216                                         $rating_scheme = null;
4217                                         $rating_value = null;
4218                                         if (isset($rating['attribs']['']['scheme']))
4219                                         {
4220                                                 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4221                                         }
4222                                         else
4223                                         {
4224                                                 $rating_scheme = 'urn:simple';
4225                                         }
4226                                         if (isset($rating['data']))
4227                                         {
4228                                                 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4229                                         }
4230                                         $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
4231                                 }
4232                         }
4233                         elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
4234                         {
4235                                 foreach ($ratings as $rating)
4236                                 {
4237                                         $rating_scheme = 'urn:itunes';
4238                                         $rating_value = null;
4239                                         if (isset($rating['data']))
4240                                         {
4241                                                 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4242                                         }
4243                                         $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
4244                                 }
4245                         }
4246                         elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
4247                         {
4248                                 foreach ($ratings as $rating)
4249                                 {
4250                                         $rating_scheme = null;
4251                                         $rating_value = null;
4252                                         if (isset($rating['attribs']['']['scheme']))
4253                                         {
4254                                                 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4255                                         }
4256                                         else
4257                                         {
4258                                                 $rating_scheme = 'urn:simple';
4259                                         }
4260                                         if (isset($rating['data']))
4261                                         {
4262                                                 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4263                                         }
4264                                         $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
4265                                 }
4266                         }
4267                         elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
4268                         {
4269                                 foreach ($ratings as $rating)
4270                                 {
4271                                         $rating_scheme = 'urn:itunes';
4272                                         $rating_value = null;
4273                                         if (isset($rating['data']))
4274                                         {
4275                                                 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4276                                         }
4277                                         $ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
4278                                 }
4279                         }
4280                         if (is_array($ratings_parent))
4281                         {
4282                                 $ratings_parent = array_values(SimplePie_Misc::array_unique($ratings_parent));
4283                         }
4284
4285                         // RESTRICTIONS
4286                         if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
4287                         {
4288                                 foreach ($restrictions as $restriction)
4289                                 {
4290                                         $restriction_relationship = null;
4291                                         $restriction_type = null;
4292                                         $restriction_value = null;
4293                                         if (isset($restriction['attribs']['']['relationship']))
4294                                         {
4295                                                 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4296                                         }
4297                                         if (isset($restriction['attribs']['']['type']))
4298                                         {
4299                                                 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4300                                         }
4301                                         if (isset($restriction['data']))
4302                                         {
4303                                                 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4304                                         }
4305                                         $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4306                                 }
4307                         }
4308                         elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
4309                         {
4310                                 foreach ($restrictions as $restriction)
4311                                 {
4312                                         $restriction_relationship = 'allow';
4313                                         $restriction_type = null;
4314                                         $restriction_value = 'itunes';
4315                                         if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
4316                                         {
4317                                                 $restriction_relationship = 'deny';
4318                                         }
4319                                         $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4320                                 }
4321                         }
4322                         elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
4323                         {
4324                                 foreach ($restrictions as $restriction)
4325                                 {
4326                                         $restriction_relationship = null;
4327                                         $restriction_type = null;
4328                                         $restriction_value = null;
4329                                         if (isset($restriction['attribs']['']['relationship']))
4330                                         {
4331                                                 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4332                                         }
4333                                         if (isset($restriction['attribs']['']['type']))
4334                                         {
4335                                                 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4336                                         }
4337                                         if (isset($restriction['data']))
4338                                         {
4339                                                 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4340                                         }
4341                                         $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4342                                 }
4343                         }
4344                         elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
4345                         {
4346                                 foreach ($restrictions as $restriction)
4347                                 {
4348                                         $restriction_relationship = 'allow';
4349                                         $restriction_type = null;
4350                                         $restriction_value = 'itunes';
4351                                         if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
4352                                         {
4353                                                 $restriction_relationship = 'deny';
4354                                         }
4355                                         $restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4356                                 }
4357                         }
4358                         if (is_array($restrictions_parent))
4359                         {
4360                                 $restrictions_parent = array_values(SimplePie_Misc::array_unique($restrictions_parent));
4361                         }
4362
4363                         // THUMBNAILS
4364                         if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
4365                         {
4366                                 foreach ($thumbnails as $thumbnail)
4367                                 {
4368                                         if (isset($thumbnail['attribs']['']['url']))
4369                                         {
4370                                                 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4371                                         }
4372                                 }
4373                         }
4374                         elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
4375                         {
4376                                 foreach ($thumbnails as $thumbnail)
4377                                 {
4378                                         if (isset($thumbnail['attribs']['']['url']))
4379                                         {
4380                                                 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4381                                         }
4382                                 }
4383                         }
4384
4385                         // TITLES
4386                         if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
4387                         {
4388                                 if (isset($title_parent[0]['data']))
4389                                 {
4390                                         $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4391                                 }
4392                         }
4393                         elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
4394                         {
4395                                 if (isset($title_parent[0]['data']))
4396                                 {
4397                                         $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4398                                 }
4399                         }
4400
4401                         // Clear the memory
4402                         unset($parent);
4403
4404                         // Attributes
4405                         $bitrate = null;
4406                         $channels = null;
4407                         $duration = null;
4408                         $expression = null;
4409                         $framerate = null;
4410                         $height = null;
4411                         $javascript = null;
4412                         $lang = null;
4413                         $length = null;
4414                         $medium = null;
4415                         $samplingrate = null;
4416                         $type = null;
4417                         $url = null;
4418                         $width = null;
4419
4420                         // Elements
4421                         $captions = null;
4422                         $categories = null;
4423                         $copyrights = null;
4424                         $credits = null;
4425                         $description = null;
4426                         $hashes = null;
4427                         $keywords = null;
4428                         $player = null;
4429                         $ratings = null;
4430                         $restrictions = null;
4431                         $thumbnails = null;
4432                         $title = null;
4433
4434                         // If we have media:group tags, loop through them.
4435                         foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
4436                         {
4437                                 if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
4438                                 {
4439                                         // If we have media:content tags, loop through them.
4440                                         foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
4441                                         {
4442                                                 if (isset($content['attribs']['']['url']))
4443                                                 {
4444                                                         // Attributes
4445                                                         $bitrate = null;
4446                                                         $channels = null;
4447                                                         $duration = null;
4448                                                         $expression = null;
4449                                                         $framerate = null;
4450                                                         $height = null;
4451                                                         $javascript = null;
4452                                                         $lang = null;
4453                                                         $length = null;
4454                                                         $medium = null;
4455                                                         $samplingrate = null;
4456                                                         $type = null;
4457                                                         $url = null;
4458                                                         $width = null;
4459
4460                                                         // Elements
4461                                                         $captions = null;
4462                                                         $categories = null;
4463                                                         $copyrights = null;
4464                                                         $credits = null;
4465                                                         $description = null;
4466                                                         $hashes = null;
4467                                                         $keywords = null;
4468                                                         $player = null;
4469                                                         $ratings = null;
4470                                                         $restrictions = null;
4471                                                         $thumbnails = null;
4472                                                         $title = null;
4473
4474                                                         // Start checking the attributes of media:content
4475                                                         if (isset($content['attribs']['']['bitrate']))
4476                                                         {
4477                                                                 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
4478                                                         }
4479                                                         if (isset($content['attribs']['']['channels']))
4480                                                         {
4481                                                                 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
4482                                                         }
4483                                                         if (isset($content['attribs']['']['duration']))
4484                                                         {
4485                                                                 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
4486                                                         }
4487                                                         else
4488                                                         {
4489                                                                 $duration = $duration_parent;
4490                                                         }
4491                                                         if (isset($content['attribs']['']['expression']))
4492                                                         {
4493                                                                 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
4494                                                         }
4495                                                         if (isset($content['attribs']['']['framerate']))
4496                                                         {
4497                                                                 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
4498                                                         }
4499                                                         if (isset($content['attribs']['']['height']))
4500                                                         {
4501                                                                 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
4502                                                         }
4503                                                         if (isset($content['attribs']['']['lang']))
4504                                                         {
4505                                                                 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
4506                                                         }
4507                                                         if (isset($content['attribs']['']['fileSize']))
4508                                                         {
4509                                                                 $length = ceil($content['attribs']['']['fileSize']);
4510                                                         }
4511                                                         if (isset($content['attribs']['']['medium']))
4512                                                         {
4513                                                                 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
4514                                                         }
4515                                                         if (isset($content['attribs']['']['samplingrate']))
4516                                                         {
4517                                                                 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
4518                                                         }
4519                                                         if (isset($content['attribs']['']['type']))
4520                                                         {
4521                                                                 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4522                                                         }
4523                                                         if (isset($content['attribs']['']['width']))
4524                                                         {
4525                                                                 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
4526                                                         }
4527                                                         $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4528
4529                                                         // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
4530
4531                                                         // CAPTIONS
4532                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
4533                                                         {
4534                                                                 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
4535                                                                 {
4536                                                                         $caption_type = null;
4537                                                                         $caption_lang = null;
4538                                                                         $caption_startTime = null;
4539                                                                         $caption_endTime = null;
4540                                                                         $caption_text = null;
4541                                                                         if (isset($caption['attribs']['']['type']))
4542                                                                         {
4543                                                                                 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4544                                                                         }
4545                                                                         if (isset($caption['attribs']['']['lang']))
4546                                                                         {
4547                                                                                 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
4548                                                                         }
4549                                                                         if (isset($caption['attribs']['']['start']))
4550                                                                         {
4551                                                                                 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
4552                                                                         }
4553                                                                         if (isset($caption['attribs']['']['end']))
4554                                                                         {
4555                                                                                 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
4556                                                                         }
4557                                                                         if (isset($caption['data']))
4558                                                                         {
4559                                                                                 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4560                                                                         }
4561                                                                         $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
4562                                                                 }
4563                                                                 if (is_array($captions))
4564                                                                 {
4565                                                                         $captions = array_values(SimplePie_Misc::array_unique($captions));
4566                                                                 }
4567                                                         }
4568                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
4569                                                         {
4570                                                                 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
4571                                                                 {
4572                                                                         $caption_type = null;
4573                                                                         $caption_lang = null;
4574                                                                         $caption_startTime = null;
4575                                                                         $caption_endTime = null;
4576                                                                         $caption_text = null;
4577                                                                         if (isset($caption['attribs']['']['type']))
4578                                                                         {
4579                                                                                 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4580                                                                         }
4581                                                                         if (isset($caption['attribs']['']['lang']))
4582                                                                         {
4583                                                                                 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
4584                                                                         }
4585                                                                         if (isset($caption['attribs']['']['start']))
4586                                                                         {
4587                                                                                 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
4588                                                                         }
4589                                                                         if (isset($caption['attribs']['']['end']))
4590                                                                         {
4591                                                                                 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
4592                                                                         }
4593                                                                         if (isset($caption['data']))
4594                                                                         {
4595                                                                                 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4596                                                                         }
4597                                                                         $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
4598                                                                 }
4599                                                                 if (is_array($captions))
4600                                                                 {
4601                                                                         $captions = array_values(SimplePie_Misc::array_unique($captions));
4602                                                                 }
4603                                                         }
4604                                                         else
4605                                                         {
4606                                                                 $captions = $captions_parent;
4607                                                         }
4608
4609                                                         // CATEGORIES
4610                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
4611                                                         {
4612                                                                 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
4613                                                                 {
4614                                                                         $term = null;
4615                                                                         $scheme = null;
4616                                                                         $label = null;
4617                                                                         if (isset($category['data']))
4618                                                                         {
4619                                                                                 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4620                                                                         }
4621                                                                         if (isset($category['attribs']['']['scheme']))
4622                                                                         {
4623                                                                                 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4624                                                                         }
4625                                                                         else
4626                                                                         {
4627                                                                                 $scheme = 'http://search.yahoo.com/mrss/category_schema';
4628                                                                         }
4629                                                                         if (isset($category['attribs']['']['label']))
4630                                                                         {
4631                                                                                 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
4632                                                                         }
4633                                                                         $categories[] =& new $this->feed->category_class($term, $scheme, $label);
4634                                                                 }
4635                                                         }
4636                                                         if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
4637                                                         {
4638                                                                 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
4639                                                                 {
4640                                                                         $term = null;
4641                                                                         $scheme = null;
4642                                                                         $label = null;
4643                                                                         if (isset($category['data']))
4644                                                                         {
4645                                                                                 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4646                                                                         }
4647                                                                         if (isset($category['attribs']['']['scheme']))
4648                                                                         {
4649                                                                                 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4650                                                                         }
4651                                                                         else
4652                                                                         {
4653                                                                                 $scheme = 'http://search.yahoo.com/mrss/category_schema';
4654                                                                         }
4655                                                                         if (isset($category['attribs']['']['label']))
4656                                                                         {
4657                                                                                 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
4658                                                                         }
4659                                                                         $categories[] =& new $this->feed->category_class($term, $scheme, $label);
4660                                                                 }
4661                                                         }
4662                                                         if (is_array($categories) && is_array($categories_parent))
4663                                                         {
4664                                                                 $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
4665                                                         }
4666                                                         elseif (is_array($categories))
4667                                                         {
4668                                                                 $categories = array_values(SimplePie_Misc::array_unique($categories));
4669                                                         }
4670                                                         elseif (is_array($categories_parent))
4671                                                         {
4672                                                                 $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
4673                                                         }
4674
4675                                                         // COPYRIGHTS
4676                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
4677                                                         {
4678                                                                 $copyright_url = null;
4679                                                                 $copyright_label = null;
4680                                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
4681                                                                 {
4682                                                                         $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
4683                                                                 }
4684                                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
4685                                                                 {
4686                                                                         $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4687                                                                 }
4688                                                                 $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
4689                                                         }
4690                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
4691                                                         {
4692                                                                 $copyright_url = null;
4693                                                                 $copyright_label = null;
4694                                                                 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
4695                                                                 {
4696                                                                         $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
4697                                                                 }
4698                                                                 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
4699                                                                 {
4700                                                                         $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4701                                                                 }
4702                                                                 $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
4703                                                         }
4704                                                         else
4705                                                         {
4706                                                                 $copyrights = $copyrights_parent;
4707                                                         }
4708
4709                                                         // CREDITS
4710                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
4711                                                         {
4712                                                                 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
4713                                                                 {
4714                                                                         $credit_role = null;
4715                                                                         $credit_scheme = null;
4716                                                                         $credit_name = null;
4717                                                                         if (isset($credit['attribs']['']['role']))
4718                                                                         {
4719                                                                                 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4720                                                                         }
4721                                                                         if (isset($credit['attribs']['']['scheme']))
4722                                                                         {
4723                                                                                 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4724                                                                         }
4725                                                                         else
4726                                                                         {
4727                                                                                 $credit_scheme = 'urn:ebu';
4728                                                                         }
4729                                                                         if (isset($credit['data']))
4730                                                                         {
4731                                                                                 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4732                                                                         }
4733                                                                         $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4734                                                                 }
4735                                                                 if (is_array($credits))
4736                                                                 {
4737                                                                         $credits = array_values(SimplePie_Misc::array_unique($credits));
4738                                                                 }
4739                                                         }
4740                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
4741                                                         {
4742                                                                 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
4743                                                                 {
4744                                                                         $credit_role = null;
4745                                                                         $credit_scheme = null;
4746                                                                         $credit_name = null;
4747                                                                         if (isset($credit['attribs']['']['role']))
4748                                                                         {
4749                                                                                 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4750                                                                         }
4751                                                                         if (isset($credit['attribs']['']['scheme']))
4752                                                                         {
4753                                                                                 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4754                                                                         }
4755                                                                         else
4756                                                                         {
4757                                                                                 $credit_scheme = 'urn:ebu';
4758                                                                         }
4759                                                                         if (isset($credit['data']))
4760                                                                         {
4761                                                                                 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4762                                                                         }
4763                                                                         $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4764                                                                 }
4765                                                                 if (is_array($credits))
4766                                                                 {
4767                                                                         $credits = array_values(SimplePie_Misc::array_unique($credits));
4768                                                                 }
4769                                                         }
4770                                                         else
4771                                                         {
4772                                                                 $credits = $credits_parent;
4773                                                         }
4774
4775                                                         // DESCRIPTION
4776                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
4777                                                         {
4778                                                                 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4779                                                         }
4780                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
4781                                                         {
4782                                                                 $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4783                                                         }
4784                                                         else
4785                                                         {
4786                                                                 $description = $description_parent;
4787                                                         }
4788
4789                                                         // HASHES
4790                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
4791                                                         {
4792                                                                 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
4793                                                                 {
4794                                                                         $value = null;
4795                                                                         $algo = null;
4796                                                                         if (isset($hash['data']))
4797                                                                         {
4798                                                                                 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4799                                                                         }
4800                                                                         if (isset($hash['attribs']['']['algo']))
4801                                                                         {
4802                                                                                 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4803                                                                         }
4804                                                                         else
4805                                                                         {
4806                                                                                 $algo = 'md5';
4807                                                                         }
4808                                                                         $hashes[] = $algo.':'.$value;
4809                                                                 }
4810                                                                 if (is_array($hashes))
4811                                                                 {
4812                                                                         $hashes = array_values(SimplePie_Misc::array_unique($hashes));
4813                                                                 }
4814                                                         }
4815                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
4816                                                         {
4817                                                                 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
4818                                                                 {
4819                                                                         $value = null;
4820                                                                         $algo = null;
4821                                                                         if (isset($hash['data']))
4822                                                                         {
4823                                                                                 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4824                                                                         }
4825                                                                         if (isset($hash['attribs']['']['algo']))
4826                                                                         {
4827                                                                                 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4828                                                                         }
4829                                                                         else
4830                                                                         {
4831                                                                                 $algo = 'md5';
4832                                                                         }
4833                                                                         $hashes[] = $algo.':'.$value;
4834                                                                 }
4835                                                                 if (is_array($hashes))
4836                                                                 {
4837                                                                         $hashes = array_values(SimplePie_Misc::array_unique($hashes));
4838                                                                 }
4839                                                         }
4840                                                         else
4841                                                         {
4842                                                                 $hashes = $hashes_parent;
4843                                                         }
4844
4845                                                         // KEYWORDS
4846                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
4847                                                         {
4848                                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
4849                                                                 {
4850                                                                         $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4851                                                                         foreach ($temp as $word)
4852                                                                         {
4853                                                                                 $keywords[] = trim($word);
4854                                                                         }
4855                                                                         unset($temp);
4856                                                                 }
4857                                                                 if (is_array($keywords))
4858                                                                 {
4859                                                                         $keywords = array_values(SimplePie_Misc::array_unique($keywords));
4860                                                                 }
4861                                                         }
4862                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
4863                                                         {
4864                                                                 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
4865                                                                 {
4866                                                                         $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4867                                                                         foreach ($temp as $word)
4868                                                                         {
4869                                                                                 $keywords[] = trim($word);
4870                                                                         }
4871                                                                         unset($temp);
4872                                                                 }
4873                                                                 if (is_array($keywords))
4874                                                                 {
4875                                                                         $keywords = array_values(SimplePie_Misc::array_unique($keywords));
4876                                                                 }
4877                                                         }
4878                                                         else
4879                                                         {
4880                                                                 $keywords = $keywords_parent;
4881                                                         }
4882
4883                                                         // PLAYER
4884                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
4885                                                         {
4886                                                                 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4887                                                         }
4888                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
4889                                                         {
4890                                                                 $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4891                                                         }
4892                                                         else
4893                                                         {
4894                                                                 $player = $player_parent;
4895                                                         }
4896
4897                                                         // RATINGS
4898                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
4899                                                         {
4900                                                                 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
4901                                                                 {
4902                                                                         $rating_scheme = null;
4903                                                                         $rating_value = null;
4904                                                                         if (isset($rating['attribs']['']['scheme']))
4905                                                                         {
4906                                                                                 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4907                                                                         }
4908                                                                         else
4909                                                                         {
4910                                                                                 $rating_scheme = 'urn:simple';
4911                                                                         }
4912                                                                         if (isset($rating['data']))
4913                                                                         {
4914                                                                                 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4915                                                                         }
4916                                                                         $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
4917                                                                 }
4918                                                                 if (is_array($ratings))
4919                                                                 {
4920                                                                         $ratings = array_values(SimplePie_Misc::array_unique($ratings));
4921                                                                 }
4922                                                         }
4923                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
4924                                                         {
4925                                                                 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
4926                                                                 {
4927                                                                         $rating_scheme = null;
4928                                                                         $rating_value = null;
4929                                                                         if (isset($rating['attribs']['']['scheme']))
4930                                                                         {
4931                                                                                 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4932                                                                         }
4933                                                                         else
4934                                                                         {
4935                                                                                 $rating_scheme = 'urn:simple';
4936                                                                         }
4937                                                                         if (isset($rating['data']))
4938                                                                         {
4939                                                                                 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4940                                                                         }
4941                                                                         $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
4942                                                                 }
4943                                                                 if (is_array($ratings))
4944                                                                 {
4945                                                                         $ratings = array_values(SimplePie_Misc::array_unique($ratings));
4946                                                                 }
4947                                                         }
4948                                                         else
4949                                                         {
4950                                                                 $ratings = $ratings_parent;
4951                                                         }
4952
4953                                                         // RESTRICTIONS
4954                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
4955                                                         {
4956                                                                 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
4957                                                                 {
4958                                                                         $restriction_relationship = null;
4959                                                                         $restriction_type = null;
4960                                                                         $restriction_value = null;
4961                                                                         if (isset($restriction['attribs']['']['relationship']))
4962                                                                         {
4963                                                                                 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4964                                                                         }
4965                                                                         if (isset($restriction['attribs']['']['type']))
4966                                                                         {
4967                                                                                 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4968                                                                         }
4969                                                                         if (isset($restriction['data']))
4970                                                                         {
4971                                                                                 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4972                                                                         }
4973                                                                         $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4974                                                                 }
4975                                                                 if (is_array($restrictions))
4976                                                                 {
4977                                                                         $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
4978                                                                 }
4979                                                         }
4980                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
4981                                                         {
4982                                                                 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
4983                                                                 {
4984                                                                         $restriction_relationship = null;
4985                                                                         $restriction_type = null;
4986                                                                         $restriction_value = null;
4987                                                                         if (isset($restriction['attribs']['']['relationship']))
4988                                                                         {
4989                                                                                 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4990                                                                         }
4991                                                                         if (isset($restriction['attribs']['']['type']))
4992                                                                         {
4993                                                                                 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4994                                                                         }
4995                                                                         if (isset($restriction['data']))
4996                                                                         {
4997                                                                                 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4998                                                                         }
4999                                                                         $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
5000                                                                 }
5001                                                                 if (is_array($restrictions))
5002                                                                 {
5003                                                                         $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
5004                                                                 }
5005                                                         }
5006                                                         else
5007                                                         {
5008                                                                 $restrictions = $restrictions_parent;
5009                                                         }
5010
5011                                                         // THUMBNAILS
5012                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
5013                                                         {
5014                                                                 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
5015                                                                 {
5016                                                                         $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5017                                                                 }
5018                                                                 if (is_array($thumbnails))
5019                                                                 {
5020                                                                         $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
5021                                                                 }
5022                                                         }
5023                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
5024                                                         {
5025                                                                 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
5026                                                                 {
5027                                                                         $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5028                                                                 }
5029                                                                 if (is_array($thumbnails))
5030                                                                 {
5031                                                                         $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
5032                                                                 }
5033                                                         }
5034                                                         else
5035                                                         {
5036                                                                 $thumbnails = $thumbnails_parent;
5037                                                         }
5038
5039                                                         // TITLES
5040                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
5041                                                         {
5042                                                                 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5043                                                         }
5044                                                         elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
5045                                                         {
5046                                                                 $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5047                                                         }
5048                                                         else
5049                                                         {
5050                                                                 $title = $title_parent;
5051                                                         }
5052
5053                                                         $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
5054                                                 }
5055                                         }
5056                                 }
5057                         }
5058
5059                         // If we have standalone media:content tags, loop through them.
5060                         if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
5061                         {
5062                                 foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
5063                                 {
5064                                         if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
5065                                         {
5066                                                 // Attributes
5067                                                 $bitrate = null;
5068                                                 $channels = null;
5069                                                 $duration = null;
5070                                                 $expression = null;
5071                                                 $framerate = null;
5072                                                 $height = null;
5073                                                 $javascript = null;
5074                                                 $lang = null;
5075                                                 $length = null;
5076                                                 $medium = null;
5077                                                 $samplingrate = null;
5078                                                 $type = null;
5079                                                 $url = null;
5080                                                 $width = null;
5081
5082                                                 // Elements
5083                                                 $captions = null;
5084                                                 $categories = null;
5085                                                 $copyrights = null;
5086                                                 $credits = null;
5087                                                 $description = null;
5088                                                 $hashes = null;
5089                                                 $keywords = null;
5090                                                 $player = null;
5091                                                 $ratings = null;
5092                                                 $restrictions = null;
5093                                                 $thumbnails = null;
5094                                                 $title = null;
5095
5096                                                 // Start checking the attributes of media:content
5097                                                 if (isset($content['attribs']['']['bitrate']))
5098                                                 {
5099                                                         $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
5100                                                 }
5101                                                 if (isset($content['attribs']['']['channels']))
5102                                                 {
5103                                                         $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
5104                                                 }
5105                                                 if (isset($content['attribs']['']['duration']))
5106                                                 {
5107                                                         $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
5108                                                 }
5109                                                 else
5110                                                 {
5111                                                         $duration = $duration_parent;
5112                                                 }
5113                                                 if (isset($content['attribs']['']['expression']))
5114                                                 {
5115                                                         $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
5116                                                 }
5117                                                 if (isset($content['attribs']['']['framerate']))
5118                                                 {
5119                                                         $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
5120                                                 }
5121                                                 if (isset($content['attribs']['']['height']))
5122                                                 {
5123                                                         $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
5124                                                 }
5125                                                 if (isset($content['attribs']['']['lang']))
5126                                                 {
5127                                                         $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
5128                                                 }
5129                                                 if (isset($content['attribs']['']['fileSize']))
5130                                                 {
5131                                                         $length = ceil($content['attribs']['']['fileSize']);
5132                                                 }
5133                                                 if (isset($content['attribs']['']['medium']))
5134                                                 {
5135                                                         $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
5136                                                 }
5137                                                 if (isset($content['attribs']['']['samplingrate']))
5138                                                 {
5139                                                         $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
5140                                                 }
5141                                                 if (isset($content['attribs']['']['type']))
5142                                                 {
5143                                                         $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5144                                                 }
5145                                                 if (isset($content['attribs']['']['width']))
5146                                                 {
5147                                                         $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
5148                                                 }
5149                                                 if (isset($content['attribs']['']['url']))
5150                                                 {
5151                                                         $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5152                                                 }
5153                                                 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
5154
5155                                                 // CAPTIONS
5156                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
5157                                                 {
5158                                                         foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
5159                                                         {
5160                                                                 $caption_type = null;
5161                                                                 $caption_lang = null;
5162                                                                 $caption_startTime = null;
5163                                                                 $caption_endTime = null;
5164                                                                 $caption_text = null;
5165                                                                 if (isset($caption['attribs']['']['type']))
5166                                                                 {
5167                                                                         $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5168                                                                 }
5169                                                                 if (isset($caption['attribs']['']['lang']))
5170                                                                 {
5171                                                                         $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
5172                                                                 }
5173                                                                 if (isset($caption['attribs']['']['start']))
5174                                                                 {
5175                                                                         $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
5176                                                                 }
5177                                                                 if (isset($caption['attribs']['']['end']))
5178                                                                 {
5179                                                                         $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
5180                                                                 }
5181                                                                 if (isset($caption['data']))
5182                                                                 {
5183                                                                         $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5184                                                                 }
5185                                                                 $captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
5186                                                         }
5187                                                         if (is_array($captions))
5188                                                         {
5189                                                                 $captions = array_values(SimplePie_Misc::array_unique($captions));
5190                                                         }
5191                                                 }
5192                                                 else
5193                                                 {
5194                                                         $captions = $captions_parent;
5195                                                 }
5196
5197                                                 // CATEGORIES
5198                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
5199                                                 {
5200                                                         foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
5201                                                         {
5202                                                                 $term = null;
5203                                                                 $scheme = null;
5204                                                                 $label = null;
5205                                                                 if (isset($category['data']))
5206                                                                 {
5207                                                                         $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5208                                                                 }
5209                                                                 if (isset($category['attribs']['']['scheme']))
5210                                                                 {
5211                                                                         $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5212                                                                 }
5213                                                                 else
5214                                                                 {
5215                                                                         $scheme = 'http://search.yahoo.com/mrss/category_schema';
5216                                                                 }
5217                                                                 if (isset($category['attribs']['']['label']))
5218                                                                 {
5219                                                                         $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
5220                                                                 }
5221                                                                 $categories[] =& new $this->feed->category_class($term, $scheme, $label);
5222                                                         }
5223                                                 }
5224                                                 if (is_array($categories) && is_array($categories_parent))
5225                                                 {
5226                                                         $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
5227                                                 }
5228                                                 elseif (is_array($categories))
5229                                                 {
5230                                                         $categories = array_values(SimplePie_Misc::array_unique($categories));
5231                                                 }
5232                                                 elseif (is_array($categories_parent))
5233                                                 {
5234                                                         $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
5235                                                 }
5236                                                 else
5237                                                 {
5238                                                         $categories = null;
5239                                                 }
5240
5241                                                 // COPYRIGHTS
5242                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
5243                                                 {
5244                                                         $copyright_url = null;
5245                                                         $copyright_label = null;
5246                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
5247                                                         {
5248                                                                 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
5249                                                         }
5250                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
5251                                                         {
5252                                                                 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5253                                                         }
5254                                                         $copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
5255                                                 }
5256                                                 else
5257                                                 {
5258                                                         $copyrights = $copyrights_parent;
5259                                                 }
5260
5261                                                 // CREDITS
5262                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
5263                                                 {
5264                                                         foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
5265                                                         {
5266                                                                 $credit_role = null;
5267                                                                 $credit_scheme = null;
5268                                                                 $credit_name = null;
5269                                                                 if (isset($credit['attribs']['']['role']))
5270                                                                 {
5271                                                                         $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
5272                                                                 }
5273                                                                 if (isset($credit['attribs']['']['scheme']))
5274                                                                 {
5275                                                                         $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5276                                                                 }
5277                                                                 else
5278                                                                 {
5279                                                                         $credit_scheme = 'urn:ebu';
5280                                                                 }
5281                                                                 if (isset($credit['data']))
5282                                                                 {
5283                                                                         $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5284                                                                 }
5285                                                                 $credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
5286                                                         }
5287                                                         if (is_array($credits))
5288                                                         {
5289                                                                 $credits = array_values(SimplePie_Misc::array_unique($credits));
5290                                                         }
5291                                                 }
5292                                                 else
5293                                                 {
5294                                                         $credits = $credits_parent;
5295                                                 }
5296
5297                                                 // DESCRIPTION
5298                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
5299                                                 {
5300                                                         $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5301                                                 }
5302                                                 else
5303                                                 {
5304                                                         $description = $description_parent;
5305                                                 }
5306
5307                                                 // HASHES
5308                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
5309                                                 {
5310                                                         foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
5311                                                         {
5312                                                                 $value = null;
5313                                                                 $algo = null;
5314                                                                 if (isset($hash['data']))
5315                                                                 {
5316                                                                         $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5317                                                                 }
5318                                                                 if (isset($hash['attribs']['']['algo']))
5319                                                                 {
5320                                                                         $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
5321                                                                 }
5322                                                                 else
5323                                                                 {
5324                                                                         $algo = 'md5';
5325                                                                 }
5326                                                                 $hashes[] = $algo.':'.$value;
5327                                                         }
5328                                                         if (is_array($hashes))
5329                                                         {
5330                                                                 $hashes = array_values(SimplePie_Misc::array_unique($hashes));
5331                                                         }
5332                                                 }
5333                                                 else
5334                                                 {
5335                                                         $hashes = $hashes_parent;
5336                                                 }
5337
5338                                                 // KEYWORDS
5339                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
5340                                                 {
5341                                                         if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
5342                                                         {
5343                                                                 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
5344                                                                 foreach ($temp as $word)
5345                                                                 {
5346                                                                         $keywords[] = trim($word);
5347                                                                 }
5348                                                                 unset($temp);
5349                                                         }
5350                                                         if (is_array($keywords))
5351                                                         {
5352                                                                 $keywords = array_values(SimplePie_Misc::array_unique($keywords));
5353                                                         }
5354                                                 }
5355                                                 else
5356                                                 {
5357                                                         $keywords = $keywords_parent;
5358                                                 }
5359
5360                                                 // PLAYER
5361                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
5362                                                 {
5363                                                         $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5364                                                 }
5365                                                 else
5366                                                 {
5367                                                         $player = $player_parent;
5368                                                 }
5369
5370                                                 // RATINGS
5371                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
5372                                                 {
5373                                                         foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
5374                                                         {
5375                                                                 $rating_scheme = null;
5376                                                                 $rating_value = null;
5377                                                                 if (isset($rating['attribs']['']['scheme']))
5378                                                                 {
5379                                                                         $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5380                                                                 }
5381                                                                 else
5382                                                                 {
5383                                                                         $rating_scheme = 'urn:simple';
5384                                                                 }
5385                                                                 if (isset($rating['data']))
5386                                                                 {
5387                                                                         $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5388                                                                 }
5389                                                                 $ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
5390                                                         }
5391                                                         if (is_array($ratings))
5392                                                         {
5393                                                                 $ratings = array_values(SimplePie_Misc::array_unique($ratings));
5394                                                         }
5395                                                 }
5396                                                 else
5397                                                 {
5398                                                         $ratings = $ratings_parent;
5399                                                 }
5400
5401                                                 // RESTRICTIONS
5402                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
5403                                                 {
5404                                                         foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
5405                                                         {
5406                                                                 $restriction_relationship = null;
5407                                                                 $restriction_type = null;
5408                                                                 $restriction_value = null;
5409                                                                 if (isset($restriction['attribs']['']['relationship']))
5410                                                                 {
5411                                                                         $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
5412                                                                 }
5413                                                                 if (isset($restriction['attribs']['']['type']))
5414                                                                 {
5415                                                                         $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5416                                                                 }
5417                                                                 if (isset($restriction['data']))
5418                                                                 {
5419                                                                         $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5420                                                                 }
5421                                                                 $restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
5422                                                         }
5423                                                         if (is_array($restrictions))
5424                                                         {
5425                                                                 $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
5426                                                         }
5427                                                 }
5428                                                 else
5429                                                 {
5430                                                         $restrictions = $restrictions_parent;
5431                                                 }
5432
5433                                                 // THUMBNAILS
5434                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
5435                                                 {
5436                                                         foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
5437                                                         {
5438                                                                 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5439                                                         }
5440                                                         if (is_array($thumbnails))
5441                                                         {
5442                                                                 $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
5443                                                         }
5444                                                 }
5445                                                 else
5446                                                 {
5447                                                         $thumbnails = $thumbnails_parent;
5448                                                 }
5449
5450                                                 // TITLES
5451                                                 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
5452                                                 {
5453                                                         $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5454                                                 }
5455                                                 else
5456                                                 {
5457                                                         $title = $title_parent;
5458                                                 }
5459
5460                                                 $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
5461                                         }
5462                                 }
5463                         }
5464
5465                         foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
5466                         {
5467                                 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
5468                                 {
5469                                         // Attributes
5470                                         $bitrate = null;
5471                                         $channels = null;
5472                                         $duration = null;
5473                                         $expression = null;
5474                                         $framerate = null;
5475                                         $height = null;
5476                                         $javascript = null;
5477                                         $lang = null;
5478                                         $length = null;
5479                                         $medium = null;
5480                                         $samplingrate = null;
5481                                         $type = null;
5482                                         $url = null;
5483                                         $width = null;
5484
5485                                         $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
5486                                         if (isset($link['attribs']['']['type']))
5487                                         {
5488                                                 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5489                                         }
5490                                         if (isset($link['attribs']['']['length']))
5491                                         {
5492                                                 $length = ceil($link['attribs']['']['length']);
5493                                         }
5494
5495                                         // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5496                                         $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5497                                 }
5498                         }
5499
5500                         foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
5501                         {
5502                                 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
5503                                 {
5504                                         // Attributes
5505                                         $bitrate = null;
5506                                         $channels = null;
5507                                         $duration = null;
5508                                         $expression = null;
5509                                         $framerate = null;
5510                                         $height = null;
5511                                         $javascript = null;
5512                                         $lang = null;
5513                                         $length = null;
5514                                         $medium = null;
5515                                         $samplingrate = null;
5516                                         $type = null;
5517                                         $url = null;
5518                                         $width = null;
5519
5520                                         $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
5521                                         if (isset($link['attribs']['']['type']))
5522                                         {
5523                                                 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5524                                         }
5525                                         if (isset($link['attribs']['']['length']))
5526                                         {
5527                                                 $length = ceil($link['attribs']['']['length']);
5528                                         }
5529
5530                                         // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5531                                         $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5532                                 }
5533                         }
5534
5535                         if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
5536                         {
5537                                 if (isset($enclosure[0]['attribs']['']['url']))
5538                                 {
5539                                         // Attributes
5540                                         $bitrate = null;
5541                                         $channels = null;
5542                                         $duration = null;
5543                                         $expression = null;
5544                                         $framerate = null;
5545                                         $height = null;
5546                                         $javascript = null;
5547                                         $lang = null;
5548                                         $length = null;
5549                                         $medium = null;
5550                                         $samplingrate = null;
5551                                         $type = null;
5552                                         $url = null;
5553                                         $width = null;
5554
5555                                         $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
5556                                         if (isset($enclosure[0]['attribs']['']['type']))
5557                                         {
5558                                                 $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5559                                         }
5560                                         if (isset($enclosure[0]['attribs']['']['length']))
5561                                         {
5562                                                 $length = ceil($enclosure[0]['attribs']['']['length']);
5563                                         }
5564
5565                                         // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5566                                         $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5567                                 }
5568                         }
5569
5570                         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))
5571                         {
5572                                 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5573                                 $this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5574                         }
5575
5576                         $this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures']));
5577                 }
5578                 if (!empty($this->data['enclosures']))
5579                 {
5580                         return $this->data['enclosures'];
5581                 }
5582                 else
5583                 {
5584                         return null;
5585                 }
5586         }
5587
5588         function get_latitude()
5589         {
5590                 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
5591                 {
5592                         return (float) $return[0]['data'];
5593                 }
5594                 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))
5595                 {
5596                         return (float) $match[1];
5597                 }
5598                 else
5599                 {
5600                         return null;
5601                 }
5602         }
5603
5604         function get_longitude()
5605         {
5606                 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
5607                 {
5608                         return (float) $return[0]['data'];
5609                 }
5610                 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
5611                 {
5612                         return (float) $return[0]['data'];
5613                 }
5614                 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))
5615                 {
5616                         return (float) $match[2];
5617                 }
5618                 else
5619                 {
5620                         return null;
5621                 }
5622         }
5623
5624         function get_source()
5625         {
5626                 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
5627                 {
5628                         return new $this->feed->source_class($this, $return[0]);
5629                 }
5630                 else
5631                 {
5632                         return null;
5633                 }
5634         }
5635
5636         /**
5637          * Creates the add_to_* methods' return data
5638          *
5639          * @access private
5640          * @param string $item_url String to prefix to the item permalink
5641          * @param string $title_url String to prefix to the item title
5642          * (and suffix to the item permalink)
5643          * @return mixed URL if feed exists, false otherwise
5644          */
5645         function add_to_service($item_url, $title_url = null, $summary_url = null)
5646         {
5647                 if ($this->get_permalink() !== null)
5648                 {
5649                         $return = $item_url . rawurlencode($this->get_permalink());
5650                         if ($title_url !== null && $this->get_title() !== null)
5651                         {
5652                                 $return .= $title_url . rawurlencode($this->get_title());
5653                         }
5654                         if ($summary_url !== null && $this->get_description() !== null)
5655                         {
5656                                 $return .= $summary_url . rawurlencode($this->get_description());
5657                         }
5658                         return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI);
5659                 }
5660                 else
5661                 {
5662                         return null;
5663                 }
5664         }
5665
5666         function add_to_blinklist()
5667         {
5668                 return $this->add_to_service('http://www.blinklist.com/index.php?Action=Blink/addblink.php&Description=&Url=', '&Title=');
5669         }
5670
5671         function add_to_blogmarks()
5672         {
5673                 return $this->add_to_service('http://blogmarks.net/my/new.php?mini=1&simple=1&url=', '&title=');
5674         }
5675
5676         function add_to_delicious()
5677         {
5678                 return $this->add_to_service('http://del.icio.us/post/?v=4&url=', '&title=');
5679         }
5680
5681         function add_to_digg()
5682         {
5683                 return $this->add_to_service('http://digg.com/submit?url=', '&title=', '&bodytext=');
5684         }
5685
5686         function add_to_furl()
5687         {
5688                 return $this->add_to_service('http://www.furl.net/storeIt.jsp?u=', '&t=');
5689         }
5690
5691         function add_to_magnolia()
5692         {
5693                 return $this->add_to_service('http://ma.gnolia.com/bookmarklet/add?url=', '&title=');
5694         }
5695
5696         function add_to_myweb20()
5697         {
5698                 return $this->add_to_service('http://myweb2.search.yahoo.com/myresults/bookmarklet?u=', '&t=');
5699         }
5700
5701         function add_to_newsvine()
5702         {
5703                 return $this->add_to_service('http://www.newsvine.com/_wine/save?u=', '&h=');
5704         }
5705
5706         function add_to_reddit()
5707         {
5708                 return $this->add_to_service('http://reddit.com/submit?url=', '&title=');
5709         }
5710
5711         function add_to_segnalo()
5712         {
5713                 return $this->add_to_service('http://segnalo.com/post.html.php?url=', '&title=');
5714         }
5715
5716         function add_to_simpy()
5717         {
5718                 return $this->add_to_service('http://www.simpy.com/simpy/LinkAdd.do?href=', '&title=');
5719         }
5720
5721         function add_to_spurl()
5722         {
5723                 return $this->add_to_service('http://www.spurl.net/spurl.php?v=3&url=', '&title=');
5724         }
5725
5726         function add_to_wists()
5727         {
5728                 return $this->add_to_service('http://wists.com/r.php?c=&r=', '&title=');
5729         }
5730
5731         function search_technorati()
5732         {
5733                 return $this->add_to_service('http://www.technorati.com/search/');
5734         }
5735 }
5736
5737 class SimplePie_Source
5738 {
5739         var $item;
5740         var $data = array();
5741
5742         function SimplePie_Source($item, $data)
5743         {
5744                 $this->item = $item;
5745                 $this->data = $data;
5746         }
5747
5748         function __toString()
5749         {
5750                 return md5(serialize($this->data));
5751         }
5752
5753         function get_source_tags($namespace, $tag)
5754         {
5755                 if (isset($this->data['child'][$namespace][$tag]))
5756                 {
5757                         return $this->data['child'][$namespace][$tag];
5758                 }
5759                 else
5760                 {
5761                         return null;
5762                 }
5763         }
5764
5765         function get_base($element = array())
5766         {
5767                 return $this->item->get_base($element);
5768         }
5769
5770         function sanitize($data, $type, $base = '')
5771         {
5772                 return $this->item->sanitize($data, $type, $base);
5773         }
5774
5775         function get_item()
5776         {
5777                 return $this->item;
5778         }
5779
5780         function get_title()
5781         {
5782                 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
5783                 {
5784                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
5785                 }
5786                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
5787                 {
5788                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
5789                 }
5790                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
5791                 {
5792                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
5793                 }
5794                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
5795                 {
5796                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
5797                 }
5798                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
5799                 {
5800                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
5801                 }
5802                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
5803                 {
5804                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5805                 }
5806                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
5807                 {
5808                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5809                 }
5810                 else
5811                 {
5812                         return null;
5813                 }
5814         }
5815
5816         function get_category($key = 0)
5817         {
5818                 $categories = $this->get_categories();
5819                 if (isset($categories[$key]))
5820                 {
5821                         return $categories[$key];
5822                 }
5823                 else
5824                 {
5825                         return null;
5826                 }
5827         }
5828
5829         function get_categories()
5830         {
5831                 $categories = array();
5832
5833                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
5834                 {
5835                         $term = null;
5836                         $scheme = null;
5837                         $label = null;
5838                         if (isset($category['attribs']['']['term']))
5839                         {
5840                                 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
5841                         }
5842                         if (isset($category['attribs']['']['scheme']))
5843                         {
5844                                 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5845                         }
5846                         if (isset($category['attribs']['']['label']))
5847                         {
5848                                 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
5849                         }
5850                         $categories[] =& new $this->item->feed->category_class($term, $scheme, $label);
5851                 }
5852                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
5853                 {
5854                         // This is really the label, but keep this as the term also for BC.
5855                         // Label will also work on retrieving because that falls back to term.
5856                         $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5857                         if (isset($category['attribs']['']['domain']))
5858                         {
5859                                 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
5860                         }
5861                         else
5862                         {
5863                                 $scheme = null;
5864                         }
5865                         $categories[] =& new $this->item->feed->category_class($term, $scheme, null);
5866                 }
5867                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
5868                 {
5869                         $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5870                 }
5871                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
5872                 {
5873                         $categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5874                 }
5875
5876                 if (!empty($categories))
5877                 {
5878                         return SimplePie_Misc::array_unique($categories);
5879                 }
5880                 else
5881                 {
5882                         return null;
5883                 }
5884         }
5885
5886         function get_author($key = 0)
5887         {
5888                 $authors = $this->get_authors();
5889                 if (isset($authors[$key]))
5890                 {
5891                         return $authors[$key];
5892                 }
5893                 else
5894                 {
5895                         return null;
5896                 }
5897         }
5898
5899         function get_authors()
5900         {
5901                 $authors = array();
5902                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
5903                 {
5904                         $name = null;
5905                         $uri = null;
5906                         $email = null;
5907                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
5908                         {
5909                                 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5910                         }
5911                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
5912                         {
5913                                 $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]));
5914                         }
5915                         if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
5916                         {
5917                                 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5918                         }
5919                         if ($name !== null || $email !== null || $uri !== null)
5920                         {
5921                                 $authors[] =& new $this->item->feed->author_class($name, $uri, $email);
5922                         }
5923                 }
5924                 if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
5925                 {
5926                         $name = null;
5927                         $url = null;
5928                         $email = null;
5929                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
5930                         {
5931                                 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5932                         }
5933                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
5934                         {
5935                                 $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]));
5936                         }
5937                         if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
5938                         {
5939                                 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5940                         }
5941                         if ($name !== null || $email !== null || $url !== null)
5942                         {
5943                                 $authors[] =& new $this->item->feed->author_class($name, $url, $email);
5944                         }
5945                 }
5946                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
5947                 {
5948                         $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5949                 }
5950                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
5951                 {
5952                         $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5953                 }
5954                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
5955                 {
5956                         $authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5957                 }
5958
5959                 if (!empty($authors))
5960                 {
5961                         return SimplePie_Misc::array_unique($authors);
5962                 }
5963                 else
5964                 {
5965                         return null;
5966                 }
5967         }
5968
5969         function get_contributor($key = 0)
5970         {
5971                 $contributors = $this->get_contributors();
5972                 if (isset($contributors[$key]))
5973                 {
5974                         return $contributors[$key];
5975                 }
5976                 else
5977                 {
5978                         return null;
5979                 }
5980         }
5981
5982         function get_contributors()
5983         {
5984                 $contributors = array();
5985                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
5986                 {
5987                         $name = null;
5988                         $uri = null;
5989                         $email = null;
5990                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
5991                         {
5992                                 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5993                         }
5994                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
5995                         {
5996                                 $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]));
5997                         }
5998                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
5999                         {
6000                                 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6001                         }
6002                         if ($name !== null || $email !== null || $uri !== null)
6003                         {
6004                                 $contributors[] =& new $this->item->feed->author_class($name, $uri, $email);
6005                         }
6006                 }
6007                 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
6008                 {
6009                         $name = null;
6010                         $url = null;
6011                         $email = null;
6012                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
6013                         {
6014                                 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6015                         }
6016                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
6017                         {
6018                                 $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]));
6019                         }
6020                         if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
6021                         {
6022                                 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6023                         }
6024                         if ($name !== null || $email !== null || $url !== null)
6025                         {
6026                                 $contributors[] =& new $this->item->feed->author_class($name, $url, $email);
6027                         }
6028                 }
6029
6030                 if (!empty($contributors))
6031                 {
6032                         return SimplePie_Misc::array_unique($contributors);
6033                 }
6034                 else
6035                 {
6036                         return null;
6037                 }
6038         }
6039
6040         function get_link($key = 0, $rel = 'alternate')
6041         {
6042                 $links = $this->get_links($rel);
6043                 if (isset($links[$key]))
6044                 {
6045                         return $links[$key];
6046                 }
6047                 else
6048                 {
6049                         return null;
6050                 }
6051         }
6052
6053         /**
6054          * Added for parity between the parent-level and the item/entry-level.
6055          */
6056         function get_permalink()
6057         {
6058                 return $this->get_link(0);
6059         }
6060
6061         function get_links($rel = 'alternate')
6062         {
6063                 if (!isset($this->data['links']))
6064                 {
6065                         $this->data['links'] = array();
6066                         if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
6067                         {
6068                                 foreach ($links as $link)
6069                                 {
6070                                         if (isset($link['attribs']['']['href']))
6071                                         {
6072                                                 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
6073                                                 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
6074                                         }
6075                                 }
6076                         }
6077                         if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
6078                         {
6079                                 foreach ($links as $link)
6080                                 {
6081                                         if (isset($link['attribs']['']['href']))
6082                                         {
6083                                                 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
6084                                                 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
6085
6086                                         }
6087                                 }
6088                         }
6089                         if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
6090                         {
6091                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
6092                         }
6093                         if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
6094                         {
6095                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
6096                         }
6097                         if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
6098                         {
6099                                 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
6100                         }
6101
6102                         $keys = array_keys($this->data['links']);
6103                         foreach ($keys as $key)
6104                         {
6105                                 if (SimplePie_Misc::is_isegment_nz_nc($key))
6106                                 {
6107                                         if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
6108                                         {
6109                                                 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
6110                                                 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
6111                                         }
6112                                         else
6113                                         {
6114                                                 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
6115                                         }
6116                                 }
6117                                 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
6118                                 {
6119                                         $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
6120                                 }
6121                                 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
6122                         }
6123                 }
6124
6125                 if (isset($this->data['links'][$rel]))
6126                 {
6127                         return $this->data['links'][$rel];
6128                 }
6129                 else
6130                 {
6131                         return null;
6132                 }
6133         }
6134
6135         function get_description()
6136         {
6137                 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
6138                 {
6139                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6140                 }
6141                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
6142                 {
6143                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6144                 }
6145                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
6146                 {
6147                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6148                 }
6149                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
6150                 {
6151                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6152                 }
6153                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
6154                 {
6155                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6156                 }
6157                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
6158                 {
6159                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6160                 }
6161                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
6162                 {
6163                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6164                 }
6165                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
6166                 {
6167                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
6168                 }
6169                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
6170                 {
6171                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
6172                 }
6173                 else
6174                 {
6175                         return null;
6176                 }
6177         }
6178
6179         function get_copyright()
6180         {
6181                 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
6182                 {
6183                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6184                 }
6185                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
6186                 {
6187                         return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6188                 }
6189                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
6190                 {
6191                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6192                 }
6193                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
6194                 {
6195                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6196                 }
6197                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
6198                 {
6199                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6200                 }
6201                 else
6202                 {
6203                         return null;
6204                 }
6205         }
6206
6207         function get_language()
6208         {
6209                 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
6210                 {
6211                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6212                 }
6213                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
6214                 {
6215                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6216                 }
6217                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
6218                 {
6219                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6220                 }
6221                 elseif (isset($this->data['xml_lang']))
6222                 {
6223                         return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
6224                 }
6225                 else
6226                 {
6227                         return null;
6228                 }
6229         }
6230
6231         function get_latitude()
6232         {
6233                 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
6234                 {
6235                         return (float) $return[0]['data'];
6236                 }
6237                 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))
6238                 {
6239                         return (float) $match[1];
6240                 }
6241                 else
6242                 {
6243                         return null;
6244                 }
6245         }
6246
6247         function get_longitude()
6248         {
6249                 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
6250                 {
6251                         return (float) $return[0]['data'];
6252                 }
6253                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
6254                 {
6255                         return (float) $return[0]['data'];
6256                 }
6257                 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))
6258                 {
6259                         return (float) $match[2];
6260                 }
6261                 else
6262                 {
6263                         return null;
6264                 }
6265         }
6266
6267         function get_image_url()
6268         {
6269                 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
6270                 {
6271                         return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
6272                 }
6273                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
6274                 {
6275                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
6276                 }
6277                 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
6278                 {
6279                         return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
6280                 }
6281                 else
6282                 {
6283                         return null;
6284                 }
6285         }
6286 }
6287
6288 class SimplePie_Author
6289 {
6290         var $name;
6291         var $link;
6292         var $email;
6293
6294         // Constructor, used to input the data
6295         function SimplePie_Author($name = null, $link = null, $email = null)
6296         {
6297                 $this->name = $name;
6298                 $this->link = $link;
6299                 $this->email = $email;
6300         }
6301
6302         function __toString()
6303         {
6304                 // There is no $this->data here
6305                 return md5(serialize($this));
6306         }
6307
6308         function get_name()
6309         {
6310                 if ($this->name !== null)
6311                 {
6312                         return $this->name;
6313                 }
6314                 else
6315                 {
6316                         return null;
6317                 }
6318         }
6319
6320         function get_link()
6321         {
6322                 if ($this->link !== null)
6323                 {
6324                         return $this->link;
6325                 }
6326                 else
6327                 {
6328                         return null;
6329                 }
6330         }
6331
6332         function get_email()
6333         {
6334                 if ($this->email !== null)
6335                 {
6336                         return $this->email;
6337                 }
6338                 else
6339                 {
6340                         return null;
6341                 }
6342         }
6343 }
6344
6345 class SimplePie_Category
6346 {
6347         var $term;
6348         var $scheme;
6349         var $label;
6350
6351         // Constructor, used to input the data
6352         function SimplePie_Category($term = null, $scheme = null, $label = null)
6353         {
6354                 $this->term = $term;
6355                 $this->scheme = $scheme;
6356                 $this->label = $label;
6357         }
6358
6359         function __toString()
6360         {
6361                 // There is no $this->data here
6362                 return md5(serialize($this));
6363         }
6364
6365         function get_term()
6366         {
6367                 if ($this->term !== null)
6368                 {
6369                         return $this->term;
6370                 }
6371                 else
6372                 {
6373                         return null;
6374                 }
6375         }
6376
6377         function get_scheme()
6378         {
6379                 if ($this->scheme !== null)
6380                 {
6381                         return $this->scheme;
6382                 }
6383                 else
6384                 {
6385                         return null;
6386                 }
6387         }
6388
6389         function get_label()
6390         {
6391                 if ($this->label !== null)
6392                 {
6393                         return $this->label;
6394                 }
6395                 else
6396                 {
6397                         return $this->get_term();
6398                 }
6399         }
6400 }
6401
6402 class SimplePie_Enclosure
6403 {
6404         var $bitrate;
6405         var $captions;
6406         var $categories;
6407         var $channels;
6408         var $copyright;
6409         var $credits;
6410         var $description;
6411         var $duration;
6412         var $expression;
6413         var $framerate;
6414         var $handler;
6415         var $hashes;
6416         var $height;
6417         var $javascript;
6418         var $keywords;
6419         var $lang;
6420         var $length;
6421         var $link;
6422         var $medium;
6423         var $player;
6424         var $ratings;
6425         var $restrictions;
6426         var $samplingrate;
6427         var $thumbnails;
6428         var $title;
6429         var $type;
6430         var $width;
6431
6432         // Constructor, used to input the data
6433         function SimplePie_Enclosure($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)
6434         {
6435                 $this->bitrate = $bitrate;
6436                 $this->captions = $captions;
6437                 $this->categories = $categories;
6438                 $this->channels = $channels;
6439                 $this->copyright = $copyright;
6440                 $this->credits = $credits;
6441                 $this->description = $description;
6442                 $this->duration = $duration;
6443                 $this->expression = $expression;
6444                 $this->framerate = $framerate;
6445                 $this->hashes = $hashes;
6446                 $this->height = $height;
6447                 $this->javascript = $javascript;
6448                 $this->keywords = $keywords;
6449                 $this->lang = $lang;
6450                 $this->length = $length;
6451                 $this->link = $link;
6452                 $this->medium = $medium;
6453                 $this->player = $player;
6454                 $this->ratings = $ratings;
6455                 $this->restrictions = $restrictions;
6456                 $this->samplingrate = $samplingrate;
6457                 $this->thumbnails = $thumbnails;
6458                 $this->title = $title;
6459                 $this->type = $type;
6460                 $this->width = $width;
6461                 if (class_exists('idna_convert'))
6462                 {
6463                         $idn =& new idna_convert;
6464                         $parsed = SimplePie_Misc::parse_url($link);
6465                         $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
6466                 }
6467                 $this->handler = $this->get_handler(); // Needs to load last
6468         }
6469
6470         function __toString()
6471         {
6472                 // There is no $this->data here
6473                 return md5(serialize($this));
6474         }
6475
6476         function get_bitrate()
6477         {
6478                 if ($this->bitrate !== null)
6479                 {
6480                         return $this->bitrate;
6481                 }
6482                 else
6483                 {
6484                         return null;
6485                 }
6486         }
6487
6488         function get_caption($key = 0)
6489         {
6490                 $captions = $this->get_captions();
6491                 if (isset($captions[$key]))
6492                 {
6493                         return $captions[$key];
6494                 }
6495                 else
6496                 {
6497                         return null;
6498                 }
6499         }
6500
6501         function get_captions()
6502         {
6503                 if ($this->captions !== null)
6504                 {
6505                         return $this->captions;
6506                 }
6507                 else
6508                 {
6509                         return null;
6510                 }
6511         }
6512
6513         function get_category($key = 0)
6514         {
6515                 $categories = $this->get_categories();
6516                 if (isset($categories[$key]))
6517                 {
6518                         return $categories[$key];
6519                 }
6520                 else
6521                 {
6522                         return null;
6523                 }
6524         }
6525
6526         function get_categories()
6527         {
6528                 if ($this->categories !== null)
6529                 {
6530                         return $this->categories;
6531                 }
6532                 else
6533                 {
6534                         return null;
6535                 }
6536         }
6537
6538         function get_channels()
6539         {
6540                 if ($this->channels !== null)
6541                 {
6542                         return $this->channels;
6543                 }
6544                 else
6545                 {
6546                         return null;
6547                 }
6548         }
6549
6550         function get_copyright()
6551         {
6552                 if ($this->copyright !== null)
6553                 {
6554                         return $this->copyright;
6555                 }
6556                 else
6557                 {
6558                         return null;
6559                 }
6560         }
6561
6562         function get_credit($key = 0)
6563         {
6564                 $credits = $this->get_credits();
6565                 if (isset($credits[$key]))
6566                 {
6567                         return $credits[$key];
6568                 }
6569                 else
6570                 {
6571                         return null;
6572                 }
6573         }
6574
6575         function get_credits()
6576         {
6577                 if ($this->credits !== null)
6578                 {
6579                         return $this->credits;
6580                 }
6581                 else
6582                 {
6583                         return null;
6584                 }
6585         }
6586
6587         function get_description()
6588         {
6589                 if ($this->description !== null)
6590                 {
6591                         return $this->description;
6592                 }
6593                 else
6594                 {
6595                         return null;
6596                 }
6597         }
6598
6599         function get_duration($convert = false)
6600         {
6601                 if ($this->duration !== null)
6602                 {
6603                         if ($convert)
6604                         {
6605                                 $time = SimplePie_Misc::time_hms($this->duration);
6606                                 return $time;
6607                         }
6608                         else
6609                         {
6610                                 return $this->duration;
6611                         }
6612                 }
6613                 else
6614                 {
6615                         return null;
6616                 }
6617         }
6618
6619         function get_expression()
6620         {
6621                 if ($this->expression !== null)
6622                 {
6623                         return $this->expression;
6624                 }
6625                 else
6626                 {
6627                         return 'full';
6628                 }
6629         }
6630
6631         function get_extension()
6632         {
6633                 if ($this->link !== null)
6634                 {
6635                         $url = SimplePie_Misc::parse_url($this->link);
6636                         if ($url['path'] !== '')
6637                         {
6638                                 return pathinfo($url['path'], PATHINFO_EXTENSION);
6639                         }
6640                 }
6641                 return null;
6642         }
6643
6644         function get_framerate()
6645         {
6646                 if ($this->framerate !== null)
6647                 {
6648                         return $this->framerate;
6649                 }
6650                 else
6651                 {
6652                         return null;
6653                 }
6654         }
6655
6656         function get_handler()
6657         {
6658                 return $this->get_real_type(true);
6659         }
6660
6661         function get_hash($key = 0)
6662         {
6663                 $hashes = $this->get_hashes();
6664                 if (isset($hashes[$key]))
6665                 {
6666                         return $hashes[$key];
6667                 }
6668                 else
6669                 {
6670                         return null;
6671                 }
6672         }
6673
6674         function get_hashes()
6675         {
6676                 if ($this->hashes !== null)
6677                 {
6678                         return $this->hashes;
6679                 }
6680                 else
6681                 {
6682                         return null;
6683                 }
6684         }
6685
6686         function get_height()
6687         {
6688                 if ($this->height !== null)
6689                 {
6690                         return $this->height;
6691                 }
6692                 else
6693                 {
6694                         return null;
6695                 }
6696         }
6697
6698         function get_language()
6699         {
6700                 if ($this->lang !== null)
6701                 {
6702                         return $this->lang;
6703                 }
6704                 else
6705                 {
6706                         return null;
6707                 }
6708         }
6709
6710         function get_keyword($key = 0)
6711         {
6712                 $keywords = $this->get_keywords();
6713                 if (isset($keywords[$key]))
6714                 {
6715                         return $keywords[$key];
6716                 }
6717                 else
6718                 {
6719                         return null;
6720                 }
6721         }
6722
6723         function get_keywords()
6724         {
6725                 if ($this->keywords !== null)
6726                 {
6727                         return $this->keywords;
6728                 }
6729                 else
6730                 {
6731                         return null;
6732                 }
6733         }
6734
6735         function get_length()
6736         {
6737                 if ($this->length !== null)
6738                 {
6739                         return $this->length;
6740                 }
6741                 else
6742                 {
6743                         return null;
6744                 }
6745         }
6746
6747         function get_link()
6748         {
6749                 if ($this->link !== null)
6750                 {
6751                         return urldecode($this->link);
6752                 }
6753                 else
6754                 {
6755                         return null;
6756                 }
6757         }
6758
6759         function get_medium()
6760         {
6761                 if ($this->medium !== null)
6762                 {
6763                         return $this->medium;
6764                 }
6765                 else
6766                 {
6767                         return null;
6768                 }
6769         }
6770
6771         function get_player()
6772         {
6773                 if ($this->player !== null)
6774                 {
6775                         return $this->player;
6776                 }
6777                 else
6778                 {
6779                         return null;
6780                 }
6781         }
6782
6783         function get_rating($key = 0)
6784         {
6785                 $ratings = $this->get_ratings();
6786                 if (isset($ratings[$key]))
6787                 {
6788                         return $ratings[$key];
6789                 }
6790                 else
6791                 {
6792                         return null;
6793                 }
6794         }
6795
6796         function get_ratings()
6797         {
6798                 if ($this->ratings !== null)
6799                 {
6800                         return $this->ratings;
6801                 }
6802                 else
6803                 {
6804                         return null;
6805                 }
6806         }
6807
6808         function get_restriction($key = 0)
6809         {
6810                 $restrictions = $this->get_restrictions();
6811                 if (isset($restrictions[$key]))
6812                 {
6813                         return $restrictions[$key];
6814                 }
6815                 else
6816                 {
6817                         return null;
6818                 }
6819         }
6820
6821         function get_restrictions()
6822         {
6823                 if ($this->restrictions !== null)
6824                 {
6825                         return $this->restrictions;
6826                 }
6827                 else
6828                 {
6829                         return null;
6830                 }
6831         }
6832
6833         function get_sampling_rate()
6834         {
6835                 if ($this->samplingrate !== null)
6836                 {
6837                         return $this->samplingrate;
6838                 }
6839                 else
6840                 {
6841                         return null;
6842                 }
6843         }
6844
6845         function get_size()
6846         {
6847                 $length = $this->get_length();
6848                 if ($length !== null)
6849                 {
6850                         return round($length/1048576, 2);
6851                 }
6852                 else
6853                 {
6854                         return null;
6855                 }
6856         }
6857
6858         function get_thumbnail($key = 0)
6859         {
6860                 $thumbnails = $this->get_thumbnails();
6861                 if (isset($thumbnails[$key]))
6862                 {
6863                         return $thumbnails[$key];
6864                 }
6865                 else
6866                 {
6867                         return null;
6868                 }
6869         }
6870
6871         function get_thumbnails()
6872         {
6873                 if ($this->thumbnails !== null)
6874                 {
6875                         return $this->thumbnails;
6876                 }
6877                 else
6878                 {
6879                         return null;
6880                 }
6881         }
6882
6883         function get_title()
6884         {
6885                 if ($this->title !== null)
6886                 {
6887                         return $this->title;
6888                 }
6889                 else
6890                 {
6891                         return null;
6892                 }
6893         }
6894
6895         function get_type()
6896         {
6897                 if ($this->type !== null)
6898                 {
6899                         return $this->type;
6900                 }
6901                 else
6902                 {
6903                         return null;
6904                 }
6905         }
6906
6907         function get_width()
6908         {
6909                 if ($this->width !== null)
6910                 {
6911                         return $this->width;
6912                 }
6913                 else
6914                 {
6915                         return null;
6916                 }
6917         }
6918
6919         function native_embed($options='')
6920         {
6921                 return $this->embed($options, true);
6922         }
6923
6924         /**
6925          * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
6926          */
6927         function embed($options = '', $native = false)
6928         {
6929                 // Set up defaults
6930                 $audio = '';
6931                 $video = '';
6932                 $alt = '';
6933                 $altclass = '';
6934                 $loop = 'false';
6935                 $width = 'auto';
6936                 $height = 'auto';
6937                 $bgcolor = '#ffffff';
6938                 $mediaplayer = '';
6939                 $widescreen = false;
6940                 $handler = $this->get_handler();
6941                 $type = $this->get_real_type();
6942
6943                 // Process options and reassign values as necessary
6944                 if (is_array($options))
6945                 {
6946                         extract($options);
6947                 }
6948                 else
6949                 {
6950                         $options = explode(',', $options);
6951                         foreach($options as $option)
6952                         {
6953                                 $opt = explode(':', $option, 2);
6954                                 if (isset($opt[0], $opt[1]))
6955                                 {
6956                                         $opt[0] = trim($opt[0]);
6957                                         $opt[1] = trim($opt[1]);
6958                                         switch ($opt[0])
6959                                         {
6960                                                 case 'audio':
6961                                                         $audio = $opt[1];
6962                                                         break;
6963
6964                                                 case 'video':
6965                                                         $video = $opt[1];
6966                                                         break;
6967
6968                                                 case 'alt':
6969                                                         $alt = $opt[1];
6970                                                         break;
6971
6972                                                 case 'altclass':
6973                                                         $altclass = $opt[1];
6974                                                         break;
6975
6976                                                 case 'loop':
6977                                                         $loop = $opt[1];
6978                                                         break;
6979
6980                                                 case 'width':
6981                                                         $width = $opt[1];
6982                                                         break;
6983
6984                                                 case 'height':
6985                                                         $height = $opt[1];
6986                                                         break;
6987
6988                                                 case 'bgcolor':
6989                                                         $bgcolor = $opt[1];
6990                                                         break;
6991
6992                                                 case 'mediaplayer':
6993                                                         $mediaplayer = $opt[1];
6994                                                         break;
6995
6996                                                 case 'widescreen':
6997                                                         $widescreen = $opt[1];
6998                                                         break;
6999                                         }
7000                                 }
7001                         }
7002                 }
7003
7004                 $mime = explode('/', $type, 2);
7005                 $mime = $mime[0];
7006
7007                 // Process values for 'auto'
7008                 if ($width === 'auto')
7009                 {
7010                         if ($mime === 'video')
7011                         {
7012                                 if ($height === 'auto')
7013                                 {
7014                                         $width = 480;
7015                                 }
7016                                 elseif ($widescreen)
7017                                 {
7018                                         $width = round((intval($height)/9)*16);
7019                                 }
7020                                 else
7021                                 {
7022                                         $width = round((intval($height)/3)*4);
7023                                 }
7024                         }
7025                         else
7026                         {
7027                                 $width = '100%';
7028                         }
7029                 }
7030
7031                 if ($height === 'auto')
7032                 {
7033                         if ($mime === 'audio')
7034                         {
7035                                 $height = 0;
7036                         }
7037                         elseif ($mime === 'video')
7038                         {
7039                                 if ($width === 'auto')
7040                                 {
7041                                         if ($widescreen)
7042                                         {
7043                                                 $height = 270;
7044                                         }
7045                                         else
7046                                         {
7047                                                 $height = 360;
7048                                         }
7049                                 }
7050                                 elseif ($widescreen)
7051                                 {
7052                                         $height = round((intval($width)/16)*9);
7053                                 }
7054                                 else
7055                                 {
7056                                         $height = round((intval($width)/4)*3);
7057                                 }
7058                         }
7059                         else
7060                         {
7061                                 $height = 376;
7062                         }
7063                 }
7064                 elseif ($mime === 'audio')
7065                 {
7066                         $height = 0;
7067                 }
7068
7069                 // Set proper placeholder value
7070                 if ($mime === 'audio')
7071                 {
7072                         $placeholder = $audio;
7073                 }
7074                 elseif ($mime === 'video')
7075                 {
7076                         $placeholder = $video;
7077                 }
7078
7079                 $embed = '';
7080
7081                 // Make sure the JS library is included
7082                 if (!$native)
7083                 {
7084                         static $javascript_outputted = null;
7085                         if (!$javascript_outputted && $this->javascript)
7086                         {
7087                                 $embed .= '<script type="text/javascript" src="?' . htmlspecialchars($this->javascript) . '"></script>';
7088                                 $javascript_outputted = true;
7089                         }
7090                 }
7091
7092                 // Odeo Feed MP3's
7093                 if ($handler === 'odeo')
7094                 {
7095                         if ($native)
7096                         {
7097                                 $embed .= '<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://adobe.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url=' . $this->get_link() . '"></embed>';
7098                         }
7099                         else
7100                         {
7101                                 $embed .= '<script type="text/javascript">embed_odeo("' . $this->get_link() . '");</script>';
7102                         }
7103                 }
7104
7105                 // Flash
7106                 elseif ($handler === 'flash')
7107                 {
7108                         if ($native)
7109                         {
7110                                 $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>";
7111                         }
7112                         else
7113                         {
7114                                 $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
7115                         }
7116                 }
7117
7118                 // Flash Media Player file types.
7119                 // Preferred handler for MP3 file types.
7120                 elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
7121                 {
7122                         $height += 20;
7123                         if ($native)
7124                         {
7125                                 $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>";
7126                         }
7127                         else
7128                         {
7129                                 $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
7130                         }
7131                 }
7132
7133                 // QuickTime 7 file types.  Need to test with QuickTime 6.
7134                 // Only handle MP3's if the Flash Media Player is not present.
7135                 elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
7136                 {
7137                         $height += 16;
7138                         if ($native)
7139                         {
7140                                 if ($placeholder !== '')
7141                                 {
7142                                         $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>";
7143                                 }
7144                                 else
7145                                 {
7146                                         $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>";
7147                                 }
7148                         }
7149                         else
7150                         {
7151                                 $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
7152                         }
7153                 }
7154
7155                 // Windows Media
7156                 elseif ($handler === 'wmedia')
7157                 {
7158                         $height += 45;
7159                         if ($native)
7160                         {
7161                                 $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>";
7162                         }
7163                         else
7164                         {
7165                                 $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
7166                         }
7167                 }
7168
7169                 // Everything else
7170                 else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
7171
7172                 return $embed;
7173         }
7174
7175         function get_real_type($find_handler = false)
7176         {
7177                 // If it's Odeo, let's get it out of the way.
7178                 if (substr(strtolower($this->get_link()), 0, 15) === 'http://odeo.com')
7179                 {
7180                         return 'odeo';
7181                 }
7182
7183                 // Mime-types by handler.
7184                 $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
7185                 $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
7186                 $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
7187                 $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
7188                 $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
7189
7190                 if ($this->get_type() !== null)
7191                 {
7192                         $type = strtolower($this->type);
7193                 }
7194                 else
7195                 {
7196                         $type = null;
7197                 }
7198
7199                 // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
7200                 if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
7201                 {
7202                         switch (strtolower($this->get_extension()))
7203                         {
7204                                 // Audio mime-types
7205                                 case 'aac':
7206                                 case 'adts':
7207                                         $type = 'audio/acc';
7208                                         break;
7209
7210                                 case 'aif':
7211                                 case 'aifc':
7212                                 case 'aiff':
7213                                 case 'cdda':
7214                                         $type = 'audio/aiff';
7215                                         break;
7216
7217                                 case 'bwf':
7218                                         $type = 'audio/wav';
7219                                         break;
7220
7221                                 case 'kar':
7222                                 case 'mid':
7223                                 case 'midi':
7224                                 case 'smf':
7225                                         $type = 'audio/midi';
7226                                         break;
7227
7228                                 case 'm4a':
7229                                         $type = 'audio/x-m4a';
7230                                         break;
7231
7232                                 case 'mp3':
7233                                 case 'swa':
7234                                         $type = 'audio/mp3';
7235                                         break;
7236
7237                                 case 'wav':
7238                                         $type = 'audio/wav';
7239                                         break;
7240
7241                                 case 'wax':
7242                                         $type = 'audio/x-ms-wax';
7243                                         break;
7244
7245                                 case 'wma':
7246                                         $type = 'audio/x-ms-wma';
7247                                         break;
7248
7249                                 // Video mime-types
7250                                 case '3gp':
7251                                 case '3gpp':
7252                                         $type = 'video/3gpp';
7253                                         break;
7254
7255                                 case '3g2':
7256                                 case '3gp2':
7257                                         $type = 'video/3gpp2';
7258                                         break;
7259
7260                                 case 'asf':
7261                                         $type = 'video/x-ms-asf';
7262                                         break;
7263
7264                                 case 'flv':
7265                                         $type = 'video/x-flv';
7266                                         break;
7267
7268                                 case 'm1a':
7269                                 case 'm1s':
7270                                 case 'm1v':
7271                                 case 'm15':
7272                                 case 'm75':
7273                                 case 'mp2':
7274                                 case 'mpa':
7275                                 case 'mpeg':
7276                                 case 'mpg':
7277                                 case 'mpm':
7278                                 case 'mpv':
7279                                         $type = 'video/mpeg';
7280                                         break;
7281
7282                                 case 'm4v':
7283                                         $type = 'video/x-m4v';
7284                                         break;
7285
7286                                 case 'mov':
7287                                 case 'qt':
7288                                         $type = 'video/quicktime';
7289                                         break;
7290
7291                                 case 'mp4':
7292                                 case 'mpg4':
7293                                         $type = 'video/mp4';
7294                                         break;
7295
7296                                 case 'sdv':
7297                                         $type = 'video/sd-video';
7298                                         break;
7299
7300                                 case 'wm':
7301                                         $type = 'video/x-ms-wm';
7302                                         break;
7303
7304                                 case 'wmv':
7305                                         $type = 'video/x-ms-wmv';
7306                                         break;
7307
7308                                 case 'wvx':
7309                                         $type = 'video/x-ms-wvx';
7310                                         break;
7311
7312                                 // Flash mime-types
7313                                 case 'spl':
7314                                         $type = 'application/futuresplash';
7315                                         break;
7316
7317                                 case 'swf':
7318                                         $type = 'application/x-shockwave-flash';
7319                                         break;
7320                         }
7321                 }
7322
7323                 if ($find_handler)
7324                 {
7325                         if (in_array($type, $types_flash))
7326                         {
7327                                 return 'flash';
7328                         }
7329                         elseif (in_array($type, $types_fmedia))
7330                         {
7331                                 return 'fmedia';
7332                         }
7333                         elseif (in_array($type, $types_quicktime))
7334                         {
7335                                 return 'quicktime';
7336                         }
7337                         elseif (in_array($type, $types_wmedia))
7338                         {
7339                                 return 'wmedia';
7340                         }
7341                         elseif (in_array($type, $types_mp3))
7342                         {
7343                                 return 'mp3';
7344                         }
7345                         else
7346                         {
7347                                 return null;
7348                         }
7349                 }
7350                 else
7351                 {
7352                         return $type;
7353                 }
7354         }
7355 }
7356
7357 class SimplePie_Caption
7358 {
7359         var $type;
7360         var $lang;
7361         var $startTime;
7362         var $endTime;
7363         var $text;
7364
7365         // Constructor, used to input the data
7366         function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
7367         {
7368                 $this->type = $type;
7369                 $this->lang = $lang;
7370                 $this->startTime = $startTime;
7371                 $this->endTime = $endTime;
7372                 $this->text = $text;
7373         }
7374
7375         function __toString()
7376         {
7377                 // There is no $this->data here
7378                 return md5(serialize($this));
7379         }
7380
7381         function get_endtime()
7382         {
7383                 if ($this->endTime !== null)
7384                 {
7385                         return $this->endTime;
7386                 }
7387                 else
7388                 {
7389                         return null;
7390                 }
7391         }
7392
7393         function get_language()
7394         {
7395                 if ($this->lang !== null)
7396                 {
7397                         return $this->lang;
7398                 }
7399                 else
7400                 {
7401                         return null;
7402                 }
7403         }
7404
7405         function get_starttime()
7406         {
7407                 if ($this->startTime !== null)
7408                 {
7409                         return $this->startTime;
7410                 }
7411                 else
7412                 {
7413                         return null;
7414                 }
7415         }
7416
7417         function get_text()
7418         {
7419                 if ($this->text !== null)
7420                 {
7421                         return $this->text;
7422                 }
7423                 else
7424                 {
7425                         return null;
7426                 }
7427         }
7428
7429         function get_type()
7430         {
7431                 if ($this->type !== null)
7432                 {
7433                         return $this->type;
7434                 }
7435                 else
7436                 {
7437                         return null;
7438                 }
7439         }
7440 }
7441
7442 class SimplePie_Credit
7443 {
7444         var $role;
7445         var $scheme;
7446         var $name;
7447
7448         // Constructor, used to input the data
7449         function SimplePie_Credit($role = null, $scheme = null, $name = null)
7450         {
7451                 $this->role = $role;
7452                 $this->scheme = $scheme;
7453                 $this->name = $name;
7454         }
7455
7456         function __toString()
7457         {
7458                 // There is no $this->data here
7459                 return md5(serialize($this));
7460         }
7461
7462         function get_role()
7463         {
7464                 if ($this->role !== null)
7465                 {
7466                         return $this->role;
7467                 }
7468                 else
7469                 {
7470                         return null;
7471                 }
7472         }
7473
7474         function get_scheme()
7475         {
7476                 if ($this->scheme !== null)
7477                 {
7478                         return $this->scheme;
7479                 }
7480                 else
7481                 {
7482                         return null;
7483                 }
7484         }
7485
7486         function get_name()
7487         {
7488                 if ($this->name !== null)
7489                 {
7490                         return $this->name;
7491                 }
7492                 else
7493                 {
7494                         return null;
7495                 }
7496         }
7497 }
7498
7499 class SimplePie_Copyright
7500 {
7501         var $url;
7502         var $label;
7503
7504         // Constructor, used to input the data
7505         function SimplePie_Copyright($url = null, $label = null)
7506         {
7507                 $this->url = $url;
7508                 $this->label = $label;
7509         }
7510
7511         function __toString()
7512         {
7513                 // There is no $this->data here
7514                 return md5(serialize($this));
7515         }
7516
7517         function get_url()
7518         {
7519                 if ($this->url !== null)
7520                 {
7521                         return $this->url;
7522                 }
7523                 else
7524                 {
7525                         return null;
7526                 }
7527         }
7528
7529         function get_attribution()
7530         {
7531                 if ($this->label !== null)
7532                 {
7533                         return $this->label;
7534                 }
7535                 else
7536                 {
7537                         return null;
7538                 }
7539         }
7540 }
7541
7542 class SimplePie_Rating
7543 {
7544         var $scheme;
7545         var $value;
7546
7547         // Constructor, used to input the data
7548         function SimplePie_Rating($scheme = null, $value = null)
7549         {
7550                 $this->scheme = $scheme;
7551                 $this->value = $value;
7552         }
7553
7554         function __toString()
7555         {
7556                 // There is no $this->data here
7557                 return md5(serialize($this));
7558         }
7559
7560         function get_scheme()
7561         {
7562                 if ($this->scheme !== null)
7563                 {
7564                         return $this->scheme;
7565                 }
7566                 else
7567                 {
7568                         return null;
7569                 }
7570         }
7571
7572         function get_value()
7573         {
7574                 if ($this->value !== null)
7575                 {
7576                         return $this->value;
7577                 }
7578                 else
7579                 {
7580                         return null;
7581                 }
7582         }
7583 }
7584
7585 class SimplePie_Restriction
7586 {
7587         var $relationship;
7588         var $type;
7589         var $value;
7590
7591         // Constructor, used to input the data
7592         function SimplePie_Restriction($relationship = null, $type = null, $value = null)
7593         {
7594                 $this->relationship = $relationship;
7595                 $this->type = $type;
7596                 $this->value = $value;
7597         }
7598
7599         function __toString()
7600         {
7601                 // There is no $this->data here
7602                 return md5(serialize($this));
7603         }
7604
7605         function get_relationship()
7606         {
7607                 if ($this->relationship !== null)
7608                 {
7609                         return $this->relationship;
7610                 }
7611                 else
7612                 {
7613                         return null;
7614                 }
7615         }
7616
7617         function get_type()
7618         {
7619                 if ($this->type !== null)
7620                 {
7621                         return $this->type;
7622                 }
7623                 else
7624                 {
7625                         return null;
7626                 }
7627         }
7628
7629         function get_value()
7630         {
7631                 if ($this->value !== null)
7632                 {
7633                         return $this->value;
7634                 }
7635                 else
7636                 {
7637                         return null;
7638                 }
7639         }
7640 }
7641
7642 /**
7643  * @todo Move to properly supporting RFC2616 (HTTP/1.1)
7644  */
7645 class SimplePie_File
7646 {
7647         var $url;
7648         var $useragent;
7649         var $success = true;
7650         var $headers = array();
7651         var $body;
7652         var $status_code;
7653         var $redirects = 0;
7654         var $error;
7655         var $method = SIMPLEPIE_FILE_SOURCE_NONE;
7656
7657         function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
7658         {
7659                 if (class_exists('idna_convert'))
7660                 {
7661                         $idn =& new idna_convert;
7662                         $parsed = SimplePie_Misc::parse_url($url);
7663                         $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
7664                 }
7665                 $this->url = $url;
7666                 $this->useragent = $useragent;
7667                 if (preg_match('/^http(s)?:\/\//i', $url))
7668                 {
7669                         if ($useragent === null)
7670                         {
7671                                 $useragent = ini_get('user_agent');
7672                                 $this->useragent = $useragent;
7673                         }
7674                         if (!is_array($headers))
7675                         {
7676                                 $headers = array();
7677                         }
7678                         if (!$force_fsockopen && function_exists('curl_exec'))
7679                         {
7680                                 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
7681                                 $fp = curl_init();
7682                                 $headers2 = array();
7683                                 foreach ($headers as $key => $value)
7684                                 {
7685                                         $headers2[] = "$key: $value";
7686                                 }
7687                                 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
7688                                 {
7689                                         curl_setopt($fp, CURLOPT_ENCODING, '');
7690                                 }
7691                                 curl_setopt($fp, CURLOPT_URL, $url);
7692                                 curl_setopt($fp, CURLOPT_HEADER, 1);
7693                                 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
7694                                 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
7695                                 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
7696                                 curl_setopt($fp, CURLOPT_REFERER, $url);
7697                                 curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
7698                                 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
7699                                 if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
7700                                 {
7701                                         curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
7702                                         curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
7703                                 }
7704
7705                                 /* Enable Digest authentication and SSL -fox */
7706                                 curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false); 
7707                                 curl_setopt($fp, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
7708
7709                                 $this->headers = curl_exec($fp);
7710                                 if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
7711                                 {
7712                                         curl_setopt($fp, CURLOPT_ENCODING, 'none');
7713                                         $this->headers = curl_exec($fp);
7714                                 }
7715                                 if (curl_errno($fp))
7716                                 {
7717                                         $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
7718                                         $this->success = false;
7719                                 }
7720                                 else
7721                                 {
7722                                         $info = curl_getinfo($fp);
7723                                         curl_close($fp);
7724                                         $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
7725                                         $this->headers = array_pop($this->headers);
7726                                         $parser =& new SimplePie_HTTP_Parser($this->headers);
7727                                         if ($parser->parse())
7728                                         {
7729                                                 $this->headers = $parser->headers;
7730                                                 $this->body = $parser->body;
7731                                                 $this->status_code = $parser->status_code;
7732                                                 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)
7733                                                 {
7734                                                         $this->redirects++;
7735                                                         $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
7736                                                         return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
7737                                                 }
7738                                         }
7739                                 }
7740                         }
7741                         else
7742                         {
7743                                 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
7744                                 $url_parts = parse_url($url);
7745                                 $socket_host = $url_parts['host'];
7746                                 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
7747                                 {
7748                                         $socket_host = "ssl://$url_parts[host]";
7749                                         $url_parts['port'] = 443;
7750                                 }
7751                                 if (!isset($url_parts['port']))
7752                                 {
7753                                         $url_parts['port'] = 80;
7754                                 }
7755                                 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
7756                                 if (!$fp)
7757                                 {
7758                                         $this->error = 'fsockopen error: ' . $errstr;
7759                                         $this->success = false;
7760                                 }
7761                                 else
7762                                 {
7763                                         stream_set_timeout($fp, $timeout);
7764                                         if (isset($url_parts['path']))
7765                                         {
7766                                                 if (isset($url_parts['query']))
7767                                                 {
7768                                                         $get = "$url_parts[path]?$url_parts[query]";
7769                                                 }
7770                                                 else
7771                                                 {
7772                                                         $get = $url_parts['path'];
7773                                                 }
7774                                         }
7775                                         else
7776                                         {
7777                                                 $get = '/';
7778                                         }
7779                                         $out = "GET $get HTTP/1.0\r\n";
7780                                         $out .= "Host: $url_parts[host]\r\n";
7781                                         $out .= "User-Agent: $useragent\r\n";
7782                                         if (extension_loaded('zlib'))
7783                                         {
7784                                                 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
7785                                         }
7786
7787                                         if (isset($url_parts['user']) && isset($url_parts['pass']))
7788                                         {
7789                                                 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
7790                                         }
7791                                         foreach ($headers as $key => $value)
7792                                         {
7793                                                 $out .= "$key: $value\r\n";
7794                                         }
7795                                         $out .= "Connection: Close\r\n\r\n";
7796                                         fwrite($fp, $out);
7797
7798                                         $info = stream_get_meta_data($fp);
7799
7800                                         $this->headers = '';
7801                                         while (!$info['eof'] && !$info['timed_out'])
7802                                         {
7803                                                 $this->headers .= fread($fp, 1160);
7804                                                 $info = stream_get_meta_data($fp);
7805                                         }
7806                                         if (!$info['timed_out'])
7807                                         {
7808                                                 $parser =& new SimplePie_HTTP_Parser($this->headers);
7809                                                 if ($parser->parse())
7810                                                 {
7811                                                         $this->headers = $parser->headers;
7812                                                         $this->body = $parser->body;
7813                                                         $this->status_code = $parser->status_code;
7814                                                         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)
7815                                                         {
7816                                                                 $this->redirects++;
7817                                                                 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
7818                                                                 return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
7819                                                         }
7820                                                         if (isset($this->headers['content-encoding']))
7821                                                         {
7822                                                                 // Hey, we act dumb elsewhere, so let's do that here too
7823                                                                 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
7824                                                                 {
7825                                                                         case 'gzip':
7826                                                                         case 'x-gzip':
7827                                                                                 $decoder =& new SimplePie_gzdecode($this->body);
7828                                                                                 if (!$decoder->parse())
7829                                                                                 {
7830                                                                                         $this->error = 'Unable to decode HTTP "gzip" stream';
7831                                                                                         $this->success = false;
7832                                                                                 }
7833                                                                                 else
7834                                                                                 {
7835                                                                                         $this->body = $decoder->data;
7836                                                                                 }
7837                                                                                 break;
7838
7839                                                                         case 'deflate':
7840                                                                                 if (($body = gzuncompress($this->body)) === false)
7841                                                                                 {
7842                                                                                         if (($body = gzinflate($this->body)) === false)
7843                                                                                         {
7844                                                                                                 $this->error = 'Unable to decode HTTP "deflate" stream';
7845                                                                                                 $this->success = false;
7846                                                                                         }
7847                                                                                 }
7848                                                                                 $this->body = $body;
7849                                                                                 break;
7850
7851                                                                         default:
7852                                                                                 $this->error = 'Unknown content coding';
7853                                                                                 $this->success = false;
7854                                                                 }
7855                                                         }
7856                                                 }
7857                                         }
7858                                         else
7859                                         {
7860                                                 $this->error = 'fsocket timed out';
7861                                                 $this->success = false;
7862                                         }
7863                                         fclose($fp);
7864                                 }
7865                         }
7866                 }
7867                 else
7868                 {
7869                         $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
7870                         if (!$this->body = file_get_contents($url))
7871                         {
7872                                 $this->error = 'file_get_contents could not read the file';
7873                                 $this->success = false;
7874                         }
7875                 }
7876         }
7877 }
7878
7879 /**
7880  * HTTP Response Parser
7881  *
7882  * @package SimplePie
7883  */
7884 class SimplePie_HTTP_Parser
7885 {
7886         /**
7887          * HTTP Version
7888          *
7889          * @access public
7890          * @var float
7891          */
7892         var $http_version = 0.0;
7893
7894         /**
7895          * Status code
7896          *
7897          * @access public
7898          * @var int
7899          */
7900         var $status_code = 0;
7901
7902         /**
7903          * Reason phrase
7904          *
7905          * @access public
7906          * @var string
7907          */
7908         var $reason = '';
7909
7910         /**
7911          * Key/value pairs of the headers
7912          *
7913          * @access public
7914          * @var array
7915          */
7916         var $headers = array();
7917
7918         /**
7919          * Body of the response
7920          *
7921          * @access public
7922          * @var string
7923          */
7924         var $body = '';
7925
7926         /**
7927          * Current state of the state machine
7928          *
7929          * @access private
7930          * @var string
7931          */
7932         var $state = 'http_version';
7933
7934         /**
7935          * Input data
7936          *
7937          * @access private
7938          * @var string
7939          */
7940         var $data = '';
7941
7942         /**
7943          * Input data length (to avoid calling strlen() everytime this is needed)
7944          *
7945          * @access private
7946          * @var int
7947          */
7948         var $data_length = 0;
7949
7950         /**
7951          * Current position of the pointer
7952          *
7953          * @var int
7954          * @access private
7955          */
7956         var $position = 0;
7957
7958         /**
7959          * Name of the hedaer currently being parsed
7960          *
7961          * @access private
7962          * @var string
7963          */
7964         var $name = '';
7965
7966         /**
7967          * Value of the hedaer currently being parsed
7968          *
7969          * @access private
7970          * @var string
7971          */
7972         var $value = '';
7973
7974         /**
7975          * Create an instance of the class with the input data
7976          *
7977          * @access public
7978          * @param string $data Input data
7979          */
7980         function SimplePie_HTTP_Parser($data)
7981         {
7982                 $this->data = $data;
7983                 $this->data_length = strlen($this->data);
7984         }
7985
7986         /**
7987          * Parse the input data
7988          *
7989          * @access public
7990          * @return bool true on success, false on failure
7991          */
7992         function parse()
7993         {
7994                 while ($this->state && $this->state !== 'emit' && $this->has_data())
7995                 {
7996                         $state = $this->state;
7997                         $this->$state();
7998                 }
7999                 $this->data = '';
8000                 if ($this->state === 'emit' || $this->state === 'body')
8001                 {
8002                         return true;
8003                 }
8004                 else
8005                 {
8006                         $this->http_version = '';
8007                         $this->status_code = '';
8008                         $this->reason = '';
8009                         $this->headers = array();
8010                         $this->body = '';
8011                         return false;
8012                 }
8013         }
8014
8015         /**
8016          * Check whether there is data beyond the pointer
8017          *
8018          * @access private
8019          * @return bool true if there is further data, false if not
8020          */
8021         function has_data()
8022         {
8023                 return (bool) ($this->position < $this->data_length);
8024         }
8025
8026         /**
8027          * See if the next character is LWS
8028          *
8029          * @access private
8030          * @return bool true if the next character is LWS, false if not
8031          */
8032         function is_linear_whitespace()
8033         {
8034                 return (bool) ($this->data[$this->position] === "\x09"
8035                         || $this->data[$this->position] === "\x20"
8036                         || ($this->data[$this->position] === "\x0A"
8037                                 && isset($this->data[$this->position + 1])
8038                                 && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
8039         }
8040
8041         /**
8042          * Parse the HTTP version
8043          *
8044          * @access private
8045          */
8046         function http_version()
8047         {
8048                 if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
8049                 {
8050                         $len = strspn($this->data, '0123456789.', 5);
8051                         $this->http_version = substr($this->data, 5, $len);
8052                         $this->position += 5 + $len;
8053                         if (substr_count($this->http_version, '.') <= 1)
8054                         {
8055                                 $this->http_version = (float) $this->http_version;
8056                                 $this->position += strspn($this->data, "\x09\x20", $this->position);
8057                                 $this->state = 'status';
8058                         }
8059                         else
8060                         {
8061                                 $this->state = false;
8062                         }
8063                 }
8064                 else
8065                 {
8066                         $this->state = false;
8067                 }
8068         }
8069
8070         /**
8071          * Parse the status code
8072          *
8073          * @access private
8074          */
8075         function status()
8076         {
8077                 if ($len = strspn($this->data, '0123456789', $this->position))
8078                 {
8079                         $this->status_code = (int) substr($this->data, $this->position, $len);
8080                         $this->position += $len;
8081                         $this->state = 'reason';
8082                 }
8083                 else
8084                 {
8085                         $this->state = false;
8086                 }
8087         }
8088
8089         /**
8090          * Parse the reason phrase
8091          *
8092          * @access private
8093          */
8094         function reason()
8095         {
8096                 $len = strcspn($this->data, "\x0A", $this->position);
8097                 $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
8098                 $this->position += $len + 1;
8099                 $this->state = 'new_line';
8100         }
8101
8102         /**
8103          * Deal with a new line, shifting data around as needed
8104          *
8105          * @access private
8106          */
8107         function new_line()
8108         {
8109                 $this->value = trim($this->value, "\x0D\x20");
8110                 if ($this->name !== '' && $this->value !== '')
8111                 {
8112                         $this->name = strtolower($this->name);
8113                         if (isset($this->headers[$this->name]))
8114                         {
8115                                 $this->headers[$this->name] .= ', ' . $this->value;
8116                         }
8117                         else
8118                         {
8119                                 $this->headers[$this->name] = $this->value;
8120                         }
8121                 }
8122                 $this->name = '';
8123                 $this->value = '';
8124                 if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
8125                 {
8126                         $this->position += 2;
8127                         $this->state = 'body';
8128                 }
8129                 elseif ($this->data[$this->position] === "\x0A")
8130                 {
8131                         $this->position++;
8132                         $this->state = 'body';
8133                 }
8134                 else
8135                 {
8136                         $this->state = 'name';
8137                 }
8138         }
8139
8140         /**
8141          * Parse a header name
8142          *
8143          * @access private
8144          */
8145         function name()
8146         {
8147                 $len = strcspn($this->data, "\x0A:", $this->position);
8148                 if (isset($this->data[$this->position + $len]))
8149                 {
8150                         if ($this->data[$this->position + $len] === "\x0A")
8151                         {
8152                                 $this->position += $len;
8153                                 $this->state = 'new_line';
8154                         }
8155                         else
8156                         {
8157                                 $this->name = substr($this->data, $this->position, $len);
8158                                 $this->position += $len + 1;
8159                                 $this->state = 'value';
8160                         }
8161                 }
8162                 else
8163                 {
8164                         $this->state = false;
8165                 }
8166         }
8167
8168         /**
8169          * Parse LWS, replacing consecutive LWS characters with a single space
8170          *
8171          * @access private
8172          */
8173         function linear_whitespace()
8174         {
8175                 do
8176                 {
8177                         if (substr($this->data, $this->position, 2) === "\x0D\x0A")
8178                         {
8179                                 $this->position += 2;
8180                         }
8181                         elseif ($this->data[$this->position] === "\x0A")
8182                         {
8183                                 $this->position++;
8184                         }
8185                         $this->position += strspn($this->data, "\x09\x20", $this->position);
8186                 } while ($this->has_data() && $this->is_linear_whitespace());
8187                 $this->value .= "\x20";
8188         }
8189
8190         /**
8191          * See what state to move to while within non-quoted header values
8192          *
8193          * @access private
8194          */
8195         function value()
8196         {
8197                 if ($this->is_linear_whitespace())
8198                 {
8199                         $this->linear_whitespace();
8200                 }
8201                 else
8202                 {
8203                         switch ($this->data[$this->position])
8204                         {
8205                                 case '"':
8206                                         $this->position++;
8207                                         $this->state = 'quote';
8208                                         break;
8209
8210                                 case "\x0A":
8211                                         $this->position++;
8212                                         $this->state = 'new_line';
8213                                         break;
8214
8215                                 default:
8216                                         $this->state = 'value_char';
8217                                         break;
8218                         }
8219                 }
8220         }
8221
8222         /**
8223          * Parse a header value while outside quotes
8224          *
8225          * @access private
8226          */
8227         function value_char()
8228         {
8229                 $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
8230                 $this->value .= substr($this->data, $this->position, $len);
8231                 $this->position += $len;
8232                 $this->state = 'value';
8233         }
8234
8235         /**
8236          * See what state to move to while within quoted header values
8237          *
8238          * @access private
8239          */
8240         function quote()
8241         {
8242                 if ($this->is_linear_whitespace())
8243                 {
8244                         $this->linear_whitespace();
8245                 }
8246                 else
8247                 {
8248                         switch ($this->data[$this->position])
8249                         {
8250                                 case '"':
8251                                         $this->position++;
8252                                         $this->state = 'value';
8253                                         break;
8254
8255                                 case "\x0A":
8256                                         $this->position++;
8257                                         $this->state = 'new_line';
8258                                         break;
8259
8260                                 case '\\':
8261                                         $this->position++;
8262                                         $this->state = 'quote_escaped';
8263                                         break;
8264
8265                                 default:
8266                                         $this->state = 'quote_char';
8267                                         break;
8268                         }
8269                 }
8270         }
8271
8272         /**
8273          * Parse a header value while within quotes
8274          *
8275          * @access private
8276          */
8277         function quote_char()
8278         {
8279                 $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
8280                 $this->value .= substr($this->data, $this->position, $len);
8281                 $this->position += $len;
8282                 $this->state = 'value';
8283         }
8284
8285         /**
8286          * Parse an escaped character within quotes
8287          *
8288          * @access private
8289          */
8290         function quote_escaped()
8291         {
8292                 $this->value .= $this->data[$this->position];
8293                 $this->position++;
8294                 $this->state = 'quote';
8295         }
8296
8297         /**
8298          * Parse the body
8299          *
8300          * @access private
8301          */
8302         function body()
8303         {
8304                 $this->body = substr($this->data, $this->position);
8305                 $this->state = 'emit';
8306         }
8307 }
8308
8309 /**
8310  * gzdecode
8311  *
8312  * @package SimplePie
8313  */
8314 class SimplePie_gzdecode
8315 {
8316         /**
8317          * Compressed data
8318          *
8319          * @access private
8320          * @see gzdecode::$data
8321          */
8322         var $compressed_data;
8323
8324         /**
8325          * Size of compressed data
8326          *
8327          * @access private
8328          */
8329         var $compressed_size;
8330
8331         /**
8332          * Minimum size of a valid gzip string
8333          *
8334          * @access private
8335          */
8336         var $min_compressed_size = 18;
8337
8338         /**
8339          * Current position of pointer
8340          *
8341          * @access private
8342          */
8343         var $position = 0;
8344
8345         /**
8346          * Flags (FLG)
8347          *
8348          * @access private
8349          */
8350         var $flags;
8351
8352         /**
8353          * Uncompressed data
8354          *
8355          * @access public
8356          * @see gzdecode::$compressed_data
8357          */
8358         var $data;
8359
8360         /**
8361          * Modified time
8362          *
8363          * @access public
8364          */
8365         var $MTIME;
8366
8367         /**
8368          * Extra Flags
8369          *
8370          * @access public
8371          */
8372         var $XFL;
8373
8374         /**
8375          * Operating System
8376          *
8377          * @access public
8378          */
8379         var $OS;
8380
8381         /**
8382          * Subfield ID 1
8383          *
8384          * @access public
8385          * @see gzdecode::$extra_field
8386          * @see gzdecode::$SI2
8387          */
8388         var $SI1;
8389
8390         /**
8391          * Subfield ID 2
8392          *
8393          * @access public
8394          * @see gzdecode::$extra_field
8395          * @see gzdecode::$SI1
8396          */
8397         var $SI2;
8398
8399         /**
8400          * Extra field content
8401          *
8402          * @access public
8403          * @see gzdecode::$SI1
8404          * @see gzdecode::$SI2
8405          */
8406         var $extra_field;
8407
8408         /**
8409          * Original filename
8410          *
8411          * @access public
8412          */
8413         var $filename;
8414
8415         /**
8416          * Human readable comment
8417          *
8418          * @access public
8419          */
8420         var $comment;
8421
8422         /**
8423          * Don't allow anything to be set
8424          *
8425          * @access public
8426          */
8427         function __set($name, $value)
8428         {
8429                 trigger_error("Cannot write property $name", E_USER_ERROR);
8430         }
8431
8432         /**
8433          * Set the compressed string and related properties
8434          *
8435          * @access public
8436          */
8437         function SimplePie_gzdecode($data)
8438         {
8439                 $this->compressed_data = $data;
8440                 $this->compressed_size = strlen($data);
8441         }
8442
8443         /**
8444          * Decode the GZIP stream
8445          *
8446          * @access public
8447          */
8448         function parse()
8449         {
8450                 if ($this->compressed_size >= $this->min_compressed_size)
8451                 {
8452                         // Check ID1, ID2, and CM
8453                         if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
8454                         {
8455                                 return false;
8456                         }
8457
8458                         // Get the FLG (FLaGs)
8459                         $this->flags = ord($this->compressed_data[3]);
8460
8461                         // FLG bits above (1 << 4) are reserved
8462                         if ($this->flags > 0x1F)
8463                         {
8464                                 return false;
8465                         }
8466
8467                         // Advance the pointer after the above
8468                         $this->position += 4;
8469
8470                         // MTIME
8471                         $mtime = substr($this->compressed_data, $this->position, 4);
8472                         // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
8473                         if (current(unpack('S', "\x00\x01")) === 1)
8474                         {
8475                                 $mtime = strrev($mtime);
8476                         }
8477                         $this->MTIME = current(unpack('l', $mtime));
8478                         $this->position += 4;
8479
8480                         // Get the XFL (eXtra FLags)
8481                         $this->XFL = ord($this->compressed_data[$this->position++]);
8482
8483                         // Get the OS (Operating System)
8484                         $this->OS = ord($this->compressed_data[$this->position++]);
8485
8486                         // Parse the FEXTRA
8487                         if ($this->flags & 4)
8488                         {
8489                                 // Read subfield IDs
8490                                 $this->SI1 = $this->compressed_data[$this->position++];
8491                                 $this->SI2 = $this->compressed_data[$this->position++];
8492
8493                                 // SI2 set to zero is reserved for future use
8494                                 if ($this->SI2 === "\x00")
8495                                 {
8496                                         return false;
8497                                 }
8498
8499                                 // Get the length of the extra field
8500                                 $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
8501                                 $this->position += 2;
8502
8503                                 // Check the length of the string is still valid
8504                                 $this->min_compressed_size += $len + 4;
8505                                 if ($this->compressed_size >= $this->min_compressed_size)
8506                                 {
8507                                         // Set the extra field to the given data
8508                                         $this->extra_field = substr($this->compressed_data, $this->position, $len);
8509                                         $this->position += $len;
8510                                 }
8511                                 else
8512                                 {
8513                                         return false;
8514                                 }
8515                         }
8516
8517                         // Parse the FNAME
8518                         if ($this->flags & 8)
8519                         {
8520                                 // Get the length of the filename
8521                                 $len = strcspn($this->compressed_data, "\x00", $this->position);
8522
8523                                 // Check the length of the string is still valid
8524                                 $this->min_compressed_size += $len + 1;
8525                                 if ($this->compressed_size >= $this->min_compressed_size)
8526                                 {
8527                                         // Set the original filename to the given string
8528                                         $this->filename = substr($this->compressed_data, $this->position, $len);
8529                                         $this->position += $len + 1;
8530                                 }
8531                                 else
8532                                 {
8533                                         return false;
8534                                 }
8535                         }
8536
8537                         // Parse the FCOMMENT
8538                         if ($this->flags & 16)
8539                         {
8540                                 // Get the length of the comment
8541                                 $len = strcspn($this->compressed_data, "\x00", $this->position);
8542
8543                                 // Check the length of the string is still valid
8544                                 $this->min_compressed_size += $len + 1;
8545                                 if ($this->compressed_size >= $this->min_compressed_size)
8546                                 {
8547                                         // Set the original comment to the given string
8548                                         $this->comment = substr($this->compressed_data, $this->position, $len);
8549                                         $this->position += $len + 1;
8550                                 }
8551                                 else
8552                                 {
8553                                         return false;
8554                                 }
8555                         }
8556
8557                         // Parse the FHCRC
8558                         if ($this->flags & 2)
8559                         {
8560                                 // Check the length of the string is still valid
8561                                 $this->min_compressed_size += $len + 2;
8562                                 if ($this->compressed_size >= $this->min_compressed_size)
8563                                 {
8564                                         // Read the CRC
8565                                         $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
8566
8567                                         // Check the CRC matches
8568                                         if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
8569                                         {
8570                                                 $this->position += 2;
8571                                         }
8572                                         else
8573                                         {
8574                                                 return false;
8575                                         }
8576                                 }
8577                                 else
8578                                 {
8579                                         return false;
8580                                 }
8581                         }
8582
8583                         // Decompress the actual data
8584                         if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
8585                         {
8586                                 return false;
8587                         }
8588                         else
8589                         {
8590                                 $this->position = $this->compressed_size - 8;
8591                         }
8592
8593                         // Check CRC of data
8594                         $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
8595                         $this->position += 4;
8596                         /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
8597                         {
8598                                 return false;
8599                         }*/
8600
8601                         // Check ISIZE of data
8602                         $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
8603                         $this->position += 4;
8604                         if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
8605                         {
8606                                 return false;
8607                         }
8608
8609                         // Wow, against all odds, we've actually got a valid gzip string
8610                         return true;
8611                 }
8612                 else
8613                 {
8614                         return false;
8615                 }
8616         }
8617 }
8618
8619 class SimplePie_Cache
8620 {
8621         /**
8622          * Don't call the constructor. Please.
8623          *
8624          * @access private
8625          */
8626         function SimplePie_Cache()
8627         {
8628                 trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR);
8629         }
8630
8631         /**
8632          * Create a new SimplePie_Cache object
8633          *
8634          * @static
8635          * @access public
8636          */
8637         function create($location, $filename, $extension)
8638         {
8639                 $location_iri =& new SimplePie_IRI($location);
8640                 switch ($location_iri->get_scheme())
8641                 {
8642                         case 'mysql':
8643                                 if (extension_loaded('mysql'))
8644                                 {
8645                                         return new SimplePie_Cache_MySQL($location_iri, $filename, $extension);
8646                                 }
8647                                 break;
8648
8649                         default:
8650                                 return new SimplePie_Cache_File($location, $filename, $extension);
8651                 }
8652         }
8653 }
8654
8655 class SimplePie_Cache_File
8656 {
8657         var $location;
8658         var $filename;
8659         var $extension;
8660         var $name;
8661
8662         function SimplePie_Cache_File($location, $filename, $extension)
8663         {
8664                 $this->location = $location;
8665                 $this->filename = $filename;
8666                 $this->extension = $extension;
8667                 $this->name = "$this->location/$this->filename.$this->extension";
8668         }
8669
8670         function save($data)
8671         {
8672                 if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
8673                 {
8674                         if (is_a($data, 'SimplePie'))
8675                         {
8676                                 $data = $data->data;
8677                         }
8678
8679                         $data = serialize($data);
8680
8681                         if (function_exists('file_put_contents'))
8682                         {
8683                                 return (bool) file_put_contents($this->name, $data);
8684                         }
8685                         else
8686                         {
8687                                 $fp = fopen($this->name, 'wb');
8688                                 if ($fp)
8689                                 {
8690                                         fwrite($fp, $data);
8691                                         fclose($fp);
8692                                         return true;
8693                                 }
8694                         }
8695                 }
8696                 return false;
8697         }
8698
8699         function load()
8700         {
8701                 if (file_exists($this->name) && is_readable($this->name))
8702                 {
8703                         return unserialize(file_get_contents($this->name));
8704                 }
8705                 return false;
8706         }
8707
8708         function mtime()
8709         {
8710                 if (file_exists($this->name))
8711                 {
8712                         return filemtime($this->name);
8713                 }
8714                 return false;
8715         }
8716
8717         function touch()
8718         {
8719                 if (file_exists($this->name))
8720                 {
8721                         return touch($this->name);
8722                 }
8723                 return false;
8724         }
8725
8726         function unlink()
8727         {
8728                 if (file_exists($this->name))
8729                 {
8730                         return unlink($this->name);
8731                 }
8732                 return false;
8733         }
8734 }
8735
8736 class SimplePie_Cache_DB
8737 {
8738         function prepare_simplepie_object_for_cache($data)
8739         {
8740                 $items = $data->get_items();
8741                 $items_by_id = array();
8742
8743                 if (!empty($items))
8744                 {
8745                         foreach ($items as $item)
8746                         {
8747                                 $items_by_id[$item->get_id()] = $item;
8748                         }
8749
8750                         if (count($items_by_id) !== count($items))
8751                         {
8752                                 $items_by_id = array();
8753                                 foreach ($items as $item)
8754                                 {
8755                                         $items_by_id[$item->get_id(true)] = $item;
8756                                 }
8757                         }
8758
8759                         if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
8760                         {
8761                                 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
8762                         }
8763                         elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
8764                         {
8765                                 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
8766                         }
8767                         elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
8768                         {
8769                                 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
8770                         }
8771                         elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
8772                         {
8773                                 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
8774                         }
8775                         else
8776                         {
8777                                 $channel = null;
8778                         }
8779
8780                         if ($channel !== null)
8781                         {
8782                                 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
8783                                 {
8784                                         unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
8785                                 }
8786                                 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
8787                                 {
8788                                         unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
8789                                 }
8790                                 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
8791                                 {
8792                                         unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
8793                                 }
8794                                 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
8795                                 {
8796                                         unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
8797                                 }
8798                                 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
8799                                 {
8800                                         unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
8801                                 }
8802                         }
8803                         if (isset($data->data['items']))
8804                         {
8805                                 unset($data->data['items']);
8806                         }
8807                         if (isset($data->data['ordered_items']))
8808                         {
8809                                 unset($data->data['ordered_items']);
8810                         }
8811                 }
8812                 return array(serialize($data->data), $items_by_id);
8813         }
8814 }
8815
8816 class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
8817 {
8818         var $mysql;
8819         var $options;
8820         var $id;
8821
8822         function SimplePie_Cache_MySQL($mysql_location, $name, $extension)
8823         {
8824                 $host = $mysql_location->get_host();
8825                 if (SimplePie_Misc::stripos($host, 'unix(') === 0 && substr($host, -1) === ')')
8826                 {
8827                         $server = ':' . substr($host, 5, -1);
8828                 }
8829                 else
8830                 {
8831                         $server = $host;
8832                         if ($mysql_location->get_port() !== null)
8833                         {
8834                                 $server .= ':' . $mysql_location->get_port();
8835                         }
8836                 }
8837
8838                 if (strpos($mysql_location->get_userinfo(), ':') !== false)
8839                 {
8840                         list($username, $password) = explode(':', $mysql_location->get_userinfo(), 2);
8841                 }
8842                 else
8843                 {
8844                         $username = $mysql_location->get_userinfo();
8845                         $password = null;
8846                 }
8847
8848                 if ($this->mysql = mysql_connect($server, $username, $password))
8849                 {
8850                         $this->id = $name . $extension;
8851                         $this->options = SimplePie_Misc::parse_str($mysql_location->get_query());
8852                         if (!isset($this->options['prefix'][0]))
8853                         {
8854                                 $this->options['prefix'][0] = '';
8855                         }
8856
8857                         if (mysql_select_db(ltrim($mysql_location->get_path(), '/'))
8858                                 && mysql_query('SET NAMES utf8')
8859                                 && ($query = mysql_unbuffered_query('SHOW TABLES')))
8860                         {
8861                                 $db = array();
8862                                 while ($row = mysql_fetch_row($query))
8863                                 {
8864                                         $db[] = $row[0];
8865                                 }
8866
8867                                 if (!in_array($this->options['prefix'][0] . 'cache_data', $db))
8868                                 {
8869                                         if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . '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)))'))
8870                                         {
8871                                                 $this->mysql = null;
8872                                         }
8873                                 }
8874
8875                                 if (!in_array($this->options['prefix'][0] . 'items', $db))
8876                                 {
8877                                         if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . '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)))'))
8878                                         {
8879                                                 $this->mysql = null;
8880                                         }
8881                                 }
8882                         }
8883                         else
8884                         {
8885                                 $this->mysql = null;
8886                         }
8887                 }
8888         }
8889
8890         function save($data)
8891         {
8892                 if ($this->mysql)
8893                 {
8894                         $feed_id = "'" . mysql_real_escape_string($this->id) . "'";
8895
8896                         if (is_a($data, 'SimplePie'))
8897                         {
8898                                 if (SIMPLEPIE_PHP5)
8899                                 {
8900                                         // This keyword needs to defy coding standards for PHP4 compatibility
8901                                         $data = clone($data);
8902                                 }
8903
8904                                 $prepared = $this->prepare_simplepie_object_for_cache($data);
8905
8906                                 if ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql))
8907                                 {
8908                                         if (mysql_num_rows($query))
8909                                         {
8910                                                 $items = count($prepared[1]);
8911                                                 if ($items)
8912                                                 {
8913                                                         $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = ' . $items . ', `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id;
8914                                                 }
8915                                                 else
8916                                                 {
8917                                                         $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id;
8918                                                 }
8919
8920                                                 if (!mysql_query($sql, $this->mysql))
8921                                                 {
8922                                                         return false;
8923                                                 }
8924                                         }
8925                                         elseif (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(' . $feed_id . ', ' . count($prepared[1]) . ', \'' . mysql_real_escape_string($prepared[0]) . '\', ' . time() . ')', $this->mysql))
8926                                         {
8927                                                 return false;
8928                                         }
8929
8930                                         $ids = array_keys($prepared[1]);
8931                                         if (!empty($ids))
8932                                         {
8933                                                 foreach ($ids as $id)
8934                                                 {
8935                                                         $database_ids[] = mysql_real_escape_string($id);
8936                                                 }
8937
8938                                                 if ($query = mysql_unbuffered_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'items` WHERE `id` = \'' . implode('\' OR `id` = \'', $database_ids) . '\' AND `feed_id` = ' . $feed_id, $this->mysql))
8939                                                 {
8940                                                         $existing_ids = array();
8941                                                         while ($row = mysql_fetch_row($query))
8942                                                         {
8943                                                                 $existing_ids[] = $row[0];
8944                                                         }
8945
8946                                                         $new_ids = array_diff($ids, $existing_ids);
8947
8948                                                         foreach ($new_ids as $new_id)
8949                                                         {
8950                                                                 if (!($date = $prepared[1][$new_id]->get_date('U')))
8951                                                                 {
8952                                                                         $date = time();
8953                                                                 }
8954
8955                                                                 if (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(' . $feed_id . ', \'' . mysql_real_escape_string($new_id) . '\', \'' . mysql_real_escape_string(serialize($prepared[1][$new_id]->data)) . '\', ' . $date . ')', $this->mysql))
8956                                                                 {
8957                                                                         return false;
8958                                                                 }
8959                                                         }
8960                                                         return true;
8961                                                 }
8962                                         }
8963                                         else
8964                                         {
8965                                                 return true;
8966                                         }
8967                                 }
8968                         }
8969                         elseif ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql))
8970                         {
8971                                 if (mysql_num_rows($query))
8972                                 {
8973                                         if (mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = 0, `data` = \'' . mysql_real_escape_string(serialize($data)) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id, $this->mysql))
8974                                         {
8975                                                 return true;
8976                                         }
8977                                 }
8978                                 elseif (mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(\'' . mysql_real_escape_string($this->id) . '\', 0, \'' . mysql_real_escape_string(serialize($data)) . '\', ' . time() . ')', $this->mysql))
8979                                 {
8980                                         return true;
8981                                 }
8982                         }
8983                 }
8984                 return false;
8985         }
8986
8987         function load()
8988         {
8989                 if ($this->mysql && ($query = mysql_query('SELECT `items`, `data` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query)))
8990                 {
8991                         $data = unserialize($row[1]);
8992
8993                         if (isset($this->options['items'][0]))
8994                         {
8995                                 $items = (int) $this->options['items'][0];
8996                         }
8997                         else
8998                         {
8999                                 $items = (int) $row[0];
9000                         }
9001
9002                         if ($items !== 0)
9003                         {
9004                                 if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
9005                                 {
9006                                         $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
9007                                 }
9008                                 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
9009                                 {
9010                                         $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
9011                                 }
9012                                 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
9013                                 {
9014                                         $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
9015                                 }
9016                                 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
9017                                 {
9018                                         $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
9019                                 }
9020                                 else
9021                                 {
9022                                         $feed = null;
9023                                 }
9024
9025                                 if ($feed !== null)
9026                                 {
9027                                         $sql = 'SELECT `data` FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . '\' ORDER BY `posted` DESC';
9028                                         if ($items > 0)
9029                                         {
9030                                                 $sql .= ' LIMIT ' . $items;
9031                                         }
9032
9033                                         if ($query = mysql_unbuffered_query($sql, $this->mysql))
9034                                         {
9035                                                 while ($row = mysql_fetch_row($query))
9036                                                 {
9037                                                         $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row[0]);
9038                                                 }
9039                                         }
9040                                         else
9041                                         {
9042                                                 return false;
9043                                         }
9044                                 }
9045                         }
9046                         return $data;
9047                 }
9048                 return false;
9049         }
9050
9051         function mtime()
9052         {
9053                 if ($this->mysql && ($query = mysql_query('SELECT `mtime` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query)))
9054                 {
9055                         return $row[0];
9056                 }
9057                 else
9058                 {
9059                         return false;
9060                 }
9061         }
9062
9063         function touch()
9064         {
9065                 if ($this->mysql && ($query = mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `mtime` = ' . time() . ' WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && mysql_affected_rows($this->mysql))
9066                 {
9067                         return true;
9068                 }
9069                 else
9070                 {
9071                         return false;
9072                 }
9073         }
9074
9075         function unlink()
9076         {
9077                 if ($this->mysql && ($query = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($query2 = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)))
9078                 {
9079                         return true;
9080                 }
9081                 else
9082                 {
9083                         return false;
9084                 }
9085         }
9086 }
9087
9088 class SimplePie_Misc
9089 {
9090         function time_hms($seconds)
9091         {
9092                 $time = '';
9093
9094                 $hours = floor($seconds / 3600);
9095                 $remainder = $seconds % 3600;
9096                 if ($hours > 0)
9097                 {
9098                         $time .= $hours.':';
9099                 }
9100
9101                 $minutes = floor($remainder / 60);
9102                 $seconds = $remainder % 60;
9103                 if ($minutes < 10 && $hours > 0)
9104                 {
9105                         $minutes = '0' . $minutes;
9106                 }
9107                 if ($seconds < 10)
9108                 {
9109                         $seconds = '0' . $seconds;
9110                 }
9111
9112                 $time .= $minutes.':';
9113                 $time .= $seconds;
9114
9115                 return $time;
9116         }
9117
9118         function absolutize_url($relative, $base)
9119         {
9120                 $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
9121                 return $iri->get_iri();
9122         }
9123
9124         function remove_dot_segments($input)
9125         {
9126                 $output = '';
9127                 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
9128                 {
9129                         // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
9130                         if (strpos($input, '../') === 0)
9131                         {
9132                                 $input = substr($input, 3);
9133                         }
9134                         elseif (strpos($input, './') === 0)
9135                         {
9136                                 $input = substr($input, 2);
9137                         }
9138                         // 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,
9139                         elseif (strpos($input, '/./') === 0)
9140                         {
9141                                 $input = substr_replace($input, '/', 0, 3);
9142                         }
9143                         elseif ($input === '/.')
9144                         {
9145                                 $input = '/';
9146                         }
9147                         // 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,
9148                         elseif (strpos($input, '/../') === 0)
9149                         {
9150                                 $input = substr_replace($input, '/', 0, 4);
9151                                 $output = substr_replace($output, '', strrpos($output, '/'));
9152                         }
9153                         elseif ($input === '/..')
9154                         {
9155                                 $input = '/';
9156                                 $output = substr_replace($output, '', strrpos($output, '/'));
9157                         }
9158                         // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
9159                         elseif ($input === '.' || $input === '..')
9160                         {
9161                                 $input = '';
9162                         }
9163                         // 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
9164                         elseif (($pos = strpos($input, '/', 1)) !== false)
9165                         {
9166                                 $output .= substr($input, 0, $pos);
9167                                 $input = substr_replace($input, '', 0, $pos);
9168                         }
9169                         else
9170                         {
9171                                 $output .= $input;
9172                                 $input = '';
9173                         }
9174                 }
9175                 return $output . $input;
9176         }
9177
9178         function get_element($realname, $string)
9179         {
9180                 $return = array();
9181                 $name = preg_quote($realname, '/');
9182                 if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
9183                 {
9184                         for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
9185                         {
9186                                 $return[$i]['tag'] = $realname;
9187                                 $return[$i]['full'] = $matches[$i][0][0];
9188                                 $return[$i]['offset'] = $matches[$i][0][1];
9189                                 if (strlen($matches[$i][3][0]) <= 2)
9190                                 {
9191                                         $return[$i]['self_closing'] = true;
9192                                 }
9193                                 else
9194                                 {
9195                                         $return[$i]['self_closing'] = false;
9196                                         $return[$i]['content'] = $matches[$i][4][0];
9197                                 }
9198                                 $return[$i]['attribs'] = array();
9199                                 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))
9200                                 {
9201                                         for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
9202                                         {
9203                                                 if (count($attribs[$j]) === 2)
9204                                                 {
9205                                                         $attribs[$j][2] = $attribs[$j][1];
9206                                                 }
9207                                                 $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
9208                                         }
9209                                 }
9210                         }
9211                 }
9212                 return $return;
9213         }
9214
9215         function element_implode($element)
9216         {
9217                 $full = "<$element[tag]";
9218                 foreach ($element['attribs'] as $key => $value)
9219                 {
9220                         $key = strtolower($key);
9221                         $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
9222                 }
9223                 if ($element['self_closing'])
9224                 {
9225                         $full .= ' />';
9226                 }
9227                 else
9228                 {
9229                         $full .= ">$element[content]</$element[tag]>";
9230                 }
9231                 return $full;
9232         }
9233
9234         function error($message, $level, $file, $line)
9235         {
9236                 if ((ini_get('error_reporting') & $level) > 0)
9237                 {
9238                         switch ($level)
9239                         {
9240                                 case E_USER_ERROR:
9241                                         $note = 'PHP Error';
9242                                         break;
9243                                 case E_USER_WARNING:
9244                                         $note = 'PHP Warning';
9245                                         break;
9246                                 case E_USER_NOTICE:
9247                                         $note = 'PHP Notice';
9248                                         break;
9249                                 default:
9250                                         $note = 'Unknown Error';
9251                                         break;
9252                         }
9253
9254                         $log_error = true;
9255                         if (!function_exists('error_log'))
9256                         {
9257                                 $log_error = false;
9258                         }
9259
9260                         $log_file = @ini_get('error_log');
9261                         if (!empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file))
9262                         {
9263                                 $log_error = false;
9264                         }
9265
9266                         if ($log_error)
9267                         {
9268                                 @error_log("$note: $message in $file on line $line", 0);
9269                         }
9270                 }
9271
9272                 return $message;
9273         }
9274
9275         /**
9276          * If a file has been cached, retrieve and display it.
9277          *
9278          * This is most useful for caching images (get_favicon(), etc.),
9279          * however it works for all cached files.  This WILL NOT display ANY
9280          * file/image/page/whatever, but rather only display what has already
9281          * been cached by SimplePie.
9282          *
9283          * @access public
9284          * @see SimplePie::get_favicon()
9285          * @param str $identifier_url URL that is used to identify the content.
9286          * This may or may not be the actual URL of the live content.
9287          * @param str $cache_location Location of SimplePie's cache.  Defaults
9288          * to './cache'.
9289          * @param str $cache_extension The file extension that the file was
9290          * cached with.  Defaults to 'spc'.
9291          * @param str $cache_class Name of the cache-handling class being used
9292          * in SimplePie.  Defaults to 'SimplePie_Cache', and should be left
9293          * as-is unless you've overloaded the class.
9294          * @param str $cache_name_function Obsolete. Exists for backwards
9295          * compatibility reasons only.
9296          */
9297         function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5')
9298         {
9299                 $cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension);
9300
9301                 if ($file = $cache->load())
9302                 {
9303                         if (isset($file['headers']['content-type']))
9304                         {
9305                                 header('Content-type:' . $file['headers']['content-type']);
9306                         }
9307                         else
9308                         {
9309                                 header('Content-type: application/octet-stream');
9310                         }
9311                         header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
9312                         echo $file['body'];
9313                         exit;
9314                 }
9315
9316                 die('Cached file for ' . $identifier_url . ' cannot be found.');
9317         }
9318
9319         function fix_protocol($url, $http = 1)
9320         {
9321                 $url = SimplePie_Misc::normalize_url($url);
9322                 $parsed = SimplePie_Misc::parse_url($url);
9323                 if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
9324                 {
9325                         return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
9326                 }
9327
9328                 if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
9329                 {
9330                         return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
9331                 }
9332
9333                 if ($http === 2 && $parsed['scheme'] !== '')
9334                 {
9335                         return "feed:$url";
9336                 }
9337                 elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
9338                 {
9339                         return substr_replace($url, 'podcast', 0, 4);
9340                 }
9341                 elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
9342                 {
9343                         return substr_replace($url, 'itpc', 0, 4);
9344                 }
9345                 else
9346                 {
9347                         return $url;
9348                 }
9349         }
9350
9351         function parse_url($url)
9352         {
9353                 $iri =& new SimplePie_IRI($url);
9354                 return array(
9355                         'scheme' => (string) $iri->get_scheme(),
9356                         'authority' => (string) $iri->get_authority(),
9357                         'path' => (string) $iri->get_path(),
9358                         'query' => (string) $iri->get_query(),
9359                         'fragment' => (string) $iri->get_fragment()
9360                 );
9361         }
9362
9363         function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
9364         {
9365                 $iri =& new SimplePie_IRI('');
9366                 $iri->set_scheme($scheme);
9367                 $iri->set_authority($authority);
9368                 $iri->set_path($path);
9369                 $iri->set_query($query);
9370                 $iri->set_fragment($fragment);
9371                 return $iri->get_iri();
9372         }
9373
9374         function normalize_url($url)
9375         {
9376                 $iri =& new SimplePie_IRI($url);
9377                 return $iri->get_iri();
9378         }
9379
9380         function percent_encoding_normalization($match)
9381         {
9382                 $integer = hexdec($match[1]);
9383                 if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
9384                 {
9385                         return chr($integer);
9386                 }
9387                 else
9388                 {
9389                         return strtoupper($match[0]);
9390                 }
9391         }
9392
9393         /**
9394          * Remove bad UTF-8 bytes
9395          *
9396          * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C
9397          * FAQ: Multilingual Forms (modified to include full ASCII range)
9398          *
9399          * @author Geoffrey Sneddon
9400          * @see http://www.w3.org/International/questions/qa-forms-utf-8
9401          * @param string $str String to remove bad UTF-8 bytes from
9402          * @return string UTF-8 string
9403          */
9404         function utf8_bad_replace($str)
9405         {
9406                 if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str)))
9407                 {
9408                         return $return;
9409                 }
9410                 elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8')))
9411                 {
9412                         return $return;
9413                 }
9414                 elseif (preg_match_all('/(?:[\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+/', $str, $matches))
9415                 {
9416                         return implode("\xEF\xBF\xBD", $matches[0]);
9417                 }
9418                 elseif ($str !== '')
9419                 {
9420                         return "\xEF\xBF\xBD";
9421                 }
9422                 else
9423                 {
9424                         return '';
9425                 }
9426         }
9427
9428         /**
9429          * Converts a Windows-1252 encoded string to a UTF-8 encoded string
9430          *
9431          * @static
9432          * @access public
9433          * @param string $string Windows-1252 encoded string
9434          * @return string UTF-8 encoded string
9435          */
9436         function windows_1252_to_utf8($string)
9437         {
9438                 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");
9439
9440                 return strtr($string, $convert_table);
9441         }
9442
9443         function change_encoding($data, $input, $output)
9444         {
9445                 $input = SimplePie_Misc::encoding($input);
9446                 $output = SimplePie_Misc::encoding($output);
9447
9448                 // We fail to fail on non US-ASCII bytes
9449                 if ($input === 'US-ASCII')
9450                 {
9451                         static $non_ascii_octects = '';
9452                         if (!$non_ascii_octects)
9453                         {
9454                                 for ($i = 0x80; $i <= 0xFF; $i++)
9455                                 {
9456                                         $non_ascii_octects .= chr($i);
9457                                 }
9458                         }
9459                         $data = substr($data, 0, strcspn($data, $non_ascii_octects));
9460                 }
9461
9462                 // This is first, as behaviour of this is completely predictable
9463                 if ($input === 'windows-1252' && $output === 'UTF-8')
9464                 {
9465                         return SimplePie_Misc::windows_1252_to_utf8($data);
9466                 }
9467                 // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
9468                 elseif (function_exists('mb_convert_encoding') && @mb_convert_encoding("\x80", 'UTF-16BE', $input) !== "\x00\x80" && in_array($input, mb_list_encodings()) && ($return = @mb_convert_encoding($data, $output, $input)))
9469                 {
9470                         return $return;
9471                 }
9472                 // This is last, as behaviour of this varies with OS userland and PHP version
9473                 elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data)))
9474                 {
9475                         return $return;
9476                 }
9477                 // If we can't do anything, just fail
9478                 else
9479                 {
9480                         return false;
9481                 }
9482         }
9483
9484         /**
9485          * Normalize an encoding name
9486          *
9487          * This is automatically generated by create.php
9488          *
9489          * To generate it, run `php create.php` on the command line, and copy the
9490          * output to replace this function.
9491          *
9492          * @param string $charset Character set to standardise
9493          * @return string Standardised name
9494          */
9495         function encoding($charset)
9496         {
9497                 // Normalization from UTS #22
9498                 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
9499                 {
9500                         case 'adobestandardencoding':
9501                         case 'csadobestandardencoding':
9502                                 return 'Adobe-Standard-Encoding';
9503
9504                         case 'adobesymbolencoding':
9505                         case 'cshppsmath':
9506                                 return 'Adobe-Symbol-Encoding';
9507
9508                         case 'ami1251':
9509                         case 'amiga1251':
9510                                 return 'Amiga-1251';
9511
9512                         case 'ansix31101983':
9513                         case 'csat5001983':
9514                         case 'csiso99naplps':
9515                         case 'isoir99':
9516                         case 'naplps':
9517                                 return 'ANSI_X3.110-1983';
9518
9519                         case 'arabic7':
9520                         case 'asmo449':
9521                         case 'csiso89asmo449':
9522                         case 'iso9036':
9523                         case 'isoir89':
9524                                 return 'ASMO_449';
9525
9526                         case 'big5':
9527                         case 'csbig5':
9528                                 return 'Big5';
9529
9530                         case 'big5hkscs':
9531                                 return 'Big5-HKSCS';
9532
9533                         case 'bocu1':
9534                         case 'csbocu1':
9535                                 return 'BOCU-1';
9536
9537                         case 'brf':
9538                         case 'csbrf':
9539                                 return 'BRF';
9540
9541                         case 'bs4730':
9542                         case 'csiso4unitedkingdom':
9543                         case 'gb':
9544                         case 'iso646gb':
9545                         case 'isoir4':
9546                         case 'uk':
9547                                 return 'BS_4730';
9548
9549                         case 'bsviewdata':
9550                         case 'csiso47bsviewdata':
9551                         case 'isoir47':
9552                                 return 'BS_viewdata';
9553
9554                         case 'cesu8':
9555                         case 'cscesu8':
9556                                 return 'CESU-8';
9557
9558                         case 'ca':
9559                         case 'csa71':
9560                         case 'csaz243419851':
9561                         case 'csiso121canadian1':
9562                         case 'iso646ca':
9563                         case 'isoir121':
9564                                 return 'CSA_Z243.4-1985-1';
9565
9566                         case 'csa72':
9567                         case 'csaz243419852':
9568                         case 'csiso122canadian2':
9569                         case 'iso646ca2':
9570                         case 'isoir122':
9571                                 return 'CSA_Z243.4-1985-2';
9572
9573                         case 'csaz24341985gr':
9574                         case 'csiso123csaz24341985gr':
9575                         case 'isoir123':
9576                                 return 'CSA_Z243.4-1985-gr';
9577
9578                         case 'csiso139csn369103':
9579                         case 'csn369103':
9580                         case 'isoir139':
9581                                 return 'CSN_369103';
9582
9583                         case 'csdecmcs':
9584                         case 'dec':
9585                         case 'decmcs':
9586                                 return 'DEC-MCS';
9587
9588                         case 'csiso21german':
9589                         case 'de':
9590                         case 'din66003':
9591                         case 'iso646de':
9592                         case 'isoir21':
9593                                 return 'DIN_66003';
9594
9595                         case 'csdkus':
9596                         case 'dkus':
9597                                 return 'dk-us';
9598
9599                         case 'csiso646danish':
9600                         case 'dk':
9601                         case 'ds2089':
9602                         case 'iso646dk':
9603                                 return 'DS_2089';
9604
9605                         case 'csibmebcdicatde':
9606                         case 'ebcdicatde':
9607                                 return 'EBCDIC-AT-DE';
9608
9609                         case 'csebcdicatdea':
9610                         case 'ebcdicatdea':
9611                                 return 'EBCDIC-AT-DE-A';
9612
9613                         case 'csebcdiccafr':
9614                         case 'ebcdiccafr':
9615                                 return 'EBCDIC-CA-FR';
9616
9617                         case 'csebcdicdkno':
9618                         case 'ebcdicdkno':
9619                                 return 'EBCDIC-DK-NO';
9620
9621                         case 'csebcdicdknoa':
9622                         case 'ebcdicdknoa':
9623                                 return 'EBCDIC-DK-NO-A';
9624
9625                         case 'csebcdices':
9626                         case 'ebcdices':
9627                                 return 'EBCDIC-ES';
9628
9629                         case 'csebcdicesa':
9630                         case 'ebcdicesa':
9631                                 return 'EBCDIC-ES-A';
9632
9633                         case 'csebcdicess':
9634                         case 'ebcdicess':
9635                                 return 'EBCDIC-ES-S';
9636
9637                         case 'csebcdicfise':
9638                         case 'ebcdicfise':
9639                                 return 'EBCDIC-FI-SE';
9640
9641                         case 'csebcdicfisea':
9642                         case 'ebcdicfisea':
9643                                 return 'EBCDIC-FI-SE-A';
9644
9645                         case 'csebcdicfr':
9646                         case 'ebcdicfr':
9647                                 return 'EBCDIC-FR';
9648
9649                         case 'csebcdicit':
9650                         case 'ebcdicit':
9651                                 return 'EBCDIC-IT';
9652
9653                         case 'csebcdicpt':
9654                         case 'ebcdicpt':
9655                                 return 'EBCDIC-PT';
9656
9657                         case 'csebcdicuk':
9658                         case 'ebcdicuk':
9659                                 return 'EBCDIC-UK';
9660
9661                         case 'csebcdicus':
9662                         case 'ebcdicus':
9663                                 return 'EBCDIC-US';
9664
9665                         case 'csiso111ecmacyrillic':
9666                         case 'ecmacyrillic':
9667                         case 'isoir111':
9668                         case 'koi8e':
9669                                 return 'ECMA-cyrillic';
9670
9671                         case 'csiso17spanish':
9672                         case 'es':
9673                         case 'iso646es':
9674                         case 'isoir17':
9675                                 return 'ES';
9676
9677                         case 'csiso85spanish2':
9678                         case 'es2':
9679                         case 'iso646es2':
9680                         case 'isoir85':
9681                                 return 'ES2';
9682
9683                         case 'cseucpkdfmtjapanese':
9684                         case 'eucjp':
9685                         case 'extendedunixcodepackedformatforjapanese':
9686                                 return 'EUC-JP';
9687
9688                         case 'cseucfixwidjapanese':
9689                         case 'extendedunixcodefixedwidthforjapanese':
9690                                 return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
9691
9692                         case 'gb18030':
9693                                 return 'GB18030';
9694
9695                         case 'chinese':
9696                         case 'cp936':
9697                         case 'csgb2312':
9698                         case 'csiso58gb231280':
9699                         case 'gb2312':
9700                         case 'gb231280':
9701                         case 'gbk':
9702                         case 'isoir58':
9703                         case 'ms936':
9704                         case 'windows936':
9705                                 return 'GBK';
9706
9707                         case 'cn':
9708                         case 'csiso57gb1988':
9709                         case 'gb198880':
9710                         case 'iso646cn':
9711                         case 'isoir57':
9712                                 return 'GB_1988-80';
9713
9714                         case 'csiso153gost1976874':
9715                         case 'gost1976874':
9716                         case 'isoir153':
9717                         case 'stsev35888':
9718                                 return 'GOST_19768-74';
9719
9720                         case 'csiso150':
9721                         case 'csiso150greekccitt':
9722                         case 'greekccitt':
9723                         case 'isoir150':
9724                                 return 'greek-ccitt';
9725
9726                         case 'csiso88greek7':
9727                         case 'greek7':
9728                         case 'isoir88':
9729                                 return 'greek7';
9730
9731                         case 'csiso18greek7old':
9732                         case 'greek7old':
9733                         case 'isoir18':
9734                                 return 'greek7-old';
9735
9736                         case 'cshpdesktop':
9737                         case 'hpdesktop':
9738                                 return 'HP-DeskTop';
9739
9740                         case 'cshplegal':
9741                         case 'hplegal':
9742                                 return 'HP-Legal';
9743
9744                         case 'cshpmath8':
9745                         case 'hpmath8':
9746                                 return 'HP-Math8';
9747
9748                         case 'cshppifont':
9749                         case 'hppifont':
9750                                 return 'HP-Pi-font';
9751
9752                         case 'cshproman8':
9753                         case 'hproman8':
9754                         case 'r8':
9755                         case 'roman8':
9756                                 return 'hp-roman8';
9757
9758                         case 'hzgb2312':
9759                                 return 'HZ-GB-2312';
9760
9761                         case 'csibmsymbols':
9762                         case 'ibmsymbols':
9763                                 return 'IBM-Symbols';
9764
9765                         case 'csibmthai':
9766                         case 'ibmthai':
9767                                 return 'IBM-Thai';
9768
9769                         case 'cp37':
9770                         case 'csibm37':
9771                         case 'ebcdiccpca':
9772                         case 'ebcdiccpnl':
9773                         case 'ebcdiccpus':
9774                         case 'ebcdiccpwt':
9775                         case 'ibm37':
9776                                 return 'IBM037';
9777
9778                         case 'cp38':
9779                         case 'csibm38':
9780                         case 'ebcdicint':
9781                         case 'ibm38':
9782                                 return 'IBM038';
9783
9784                         case 'cp273':
9785                         case 'csibm273':
9786                         case 'ibm273':
9787                                 return 'IBM273';
9788
9789                         case 'cp274':
9790                         case 'csibm274':
9791                         case 'ebcdicbe':
9792                         case 'ibm274':
9793                                 return 'IBM274';
9794
9795                         case 'cp275':
9796                         case 'csibm275':
9797                         case 'ebcdicbr':
9798                         case 'ibm275':
9799                                 return 'IBM275';
9800
9801                         case 'csibm277':
9802                         case 'ebcdiccpdk':
9803                         case 'ebcdiccpno':
9804                         case 'ibm277':
9805                                 return 'IBM277';
9806
9807                         case 'cp278':
9808                         case 'csibm278':
9809                         case 'ebcdiccpfi':
9810                         case 'ebcdiccpse':
9811                         case 'ibm278':
9812                                 return 'IBM278';
9813
9814                         case 'cp280':
9815                         case 'csibm280':
9816                         case 'ebcdiccpit':
9817                         case 'ibm280':
9818                                 return 'IBM280';
9819
9820                         case 'cp281':
9821                         case 'csibm281':
9822                         case 'ebcdicjpe':
9823                         case 'ibm281':
9824                                 return 'IBM281';
9825
9826                         case 'cp284':
9827                         case 'csibm284':
9828                         case 'ebcdiccpes':
9829                         case 'ibm284':
9830                                 return 'IBM284';
9831
9832                         case 'cp285':
9833                         case 'csibm285':
9834                         case 'ebcdiccpgb':
9835                         case 'ibm285':
9836                                 return 'IBM285';
9837
9838                         case 'cp290':
9839                         case 'csibm290':
9840                         case 'ebcdicjpkana':
9841                         case 'ibm290':
9842                                 return 'IBM290';
9843
9844                         case 'cp297':
9845                         case 'csibm297':
9846                         case 'ebcdiccpfr':
9847                         case 'ibm297':
9848                                 return 'IBM297';
9849
9850                         case 'cp420':
9851                         case 'csibm420':
9852                         case 'ebcdiccpar1':
9853                         case 'ibm420':
9854                                 return 'IBM420';
9855
9856                         case 'cp423':
9857                         case 'csibm423':
9858                         case 'ebcdiccpgr':
9859                         case 'ibm423':
9860                                 return 'IBM423';
9861
9862                         case 'cp424':
9863                         case 'csibm424':
9864                         case 'ebcdiccphe':
9865                         case 'ibm424':
9866                                 return 'IBM424';
9867
9868                         case '437':
9869                         case 'cp437':
9870                         case 'cspc8codepage437':
9871                         case 'ibm437':
9872                                 return 'IBM437';
9873
9874                         case 'cp500':
9875                         case 'csibm500':
9876                         case 'ebcdiccpbe':
9877                         case 'ebcdiccpch':
9878                         case 'ibm500':
9879                                 return 'IBM500';
9880
9881                         case 'cp775':
9882                         case 'cspc775baltic':
9883                         case 'ibm775':
9884                                 return 'IBM775';
9885
9886                         case '850':
9887                         case 'cp850':
9888                         case 'cspc850multilingual':
9889                         case 'ibm850':
9890                                 return 'IBM850';
9891
9892                         case '851':
9893                         case 'cp851':
9894                         case 'csibm851':
9895                         case 'ibm851':
9896                                 return 'IBM851';
9897
9898                         case '852':
9899                         case 'cp852':
9900                         case 'cspcp852':
9901                         case 'ibm852':
9902                                 return 'IBM852';
9903
9904                         case '855':
9905                         case 'cp855':
9906                         case 'csibm855':
9907                         case 'ibm855':
9908                                 return 'IBM855';
9909
9910                         case '857':
9911                         case 'cp857':
9912                         case 'csibm857':
9913                         case 'ibm857':
9914                                 return 'IBM857';
9915
9916                         case 'ccsid858':
9917                         case 'cp858':
9918                         case 'ibm858':
9919                         case 'pcmultilingual850euro':
9920                                 return 'IBM00858';
9921
9922                         case '860':
9923                         case 'cp860':
9924                         case 'csibm860':
9925                         case 'ibm860':
9926                                 return 'IBM860';
9927
9928                         case '861':
9929                         case 'cp861':
9930                         case 'cpis':
9931                         case 'csibm861':
9932                         case 'ibm861':
9933                                 return 'IBM861';
9934
9935                         case '862':
9936                         case 'cp862':
9937                         case 'cspc862latinhebrew':
9938                         case 'ibm862':
9939                                 return 'IBM862';
9940
9941                         case '863':
9942                         case 'cp863':
9943                         case 'csibm863':
9944                         case 'ibm863':
9945                                 return 'IBM863';
9946
9947                         case 'cp864':
9948                         case 'csibm864':
9949                         case 'ibm864':
9950                                 return 'IBM864';
9951
9952                         case '865':
9953                         case 'cp865':
9954                         case 'csibm865':
9955                         case 'ibm865':
9956                                 return 'IBM865';
9957
9958                         case '866':
9959                         case 'cp866':
9960                         case 'csibm866':
9961                         case 'ibm866':
9962                                 return 'IBM866';
9963
9964                         case 'cp868':
9965                         case 'cpar':
9966                         case 'csibm868':
9967                         case 'ibm868':
9968                                 return 'IBM868';
9969
9970                         case '869':
9971                         case 'cp869':
9972                         case 'cpgr':
9973                         case 'csibm869':
9974                         case 'ibm869':
9975                                 return 'IBM869';
9976
9977                         case 'cp870':
9978                         case 'csibm870':
9979                         case 'ebcdiccproece':
9980                         case 'ebcdiccpyu':
9981                         case 'ibm870':
9982                                 return 'IBM870';
9983
9984                         case 'cp871':
9985                         case 'csibm871':
9986                         case 'ebcdiccpis':
9987                         case 'ibm871':
9988                                 return 'IBM871';
9989
9990                         case 'cp880':
9991                         case 'csibm880':
9992                         case 'ebcdiccyrillic':
9993                         case 'ibm880':
9994                                 return 'IBM880';
9995
9996                         case 'cp891':
9997                         case 'csibm891':
9998                         case 'ibm891':
9999                                 return 'IBM891';
10000
10001                         case 'cp903':
10002                         case 'csibm903':
10003                         case 'ibm903':
10004                                 return 'IBM903';
10005
10006                         case '904':
10007                         case 'cp904':
10008                         case 'csibbm904':
10009                         case 'ibm904':
10010                                 return 'IBM904';
10011
10012                         case 'cp905':
10013                         case 'csibm905':
10014                         case 'ebcdiccptr':
10015                         case 'ibm905':
10016                                 return 'IBM905';
10017
10018                         case 'cp918':
10019                         case 'csibm918':
10020                         case 'ebcdiccpar2':
10021                         case 'ibm918':
10022                                 return 'IBM918';
10023
10024                         case 'ccsid924':
10025                         case 'cp924':
10026                         case 'ebcdiclatin9euro':
10027                         case 'ibm924':
10028                                 return 'IBM00924';
10029
10030                         case 'cp1026':
10031                         case 'csibm1026':
10032                         case 'ibm1026':
10033                                 return 'IBM1026';
10034
10035                         case 'ibm1047':
10036                                 return 'IBM1047';
10037
10038                         case 'ccsid1140':
10039                         case 'cp1140':
10040                         case 'ebcdicus37euro':
10041                         case 'ibm1140':
10042                                 return 'IBM01140';
10043
10044                         case 'ccsid1141':
10045                         case 'cp1141':
10046                         case 'ebcdicde273euro':
10047                         case 'ibm1141':
10048                                 return 'IBM01141';
10049
10050                         case 'ccsid1142':
10051                         case 'cp1142':
10052                         case 'ebcdicdk277euro':
10053                         case 'ebcdicno277euro':
10054                         case 'ibm1142':
10055                                 return 'IBM01142';
10056
10057                         case 'ccsid1143':
10058                         case 'cp1143':
10059                         case 'ebcdicfi278euro':
10060                         case 'ebcdicse278euro':
10061                         case 'ibm1143':
10062                                 return 'IBM01143';
10063
10064                         case 'ccsid1144':
10065                         case 'cp1144':
10066                         case 'ebcdicit280euro':
10067                         case 'ibm1144':
10068                                 return 'IBM01144';
10069
10070                         case 'ccsid1145':
10071                         case 'cp1145':
10072                         case 'ebcdices284euro':
10073                         case 'ibm1145':
10074                                 return 'IBM01145';
10075
10076                         case 'ccsid1146':
10077                         case 'cp1146':
10078                         case 'ebcdicgb285euro':
10079                         case 'ibm1146':
10080                                 return 'IBM01146';
10081
10082                         case 'ccsid1147':
10083                         case 'cp1147':
10084                         case 'ebcdicfr297euro':
10085                         case 'ibm1147':
10086                                 return 'IBM01147';
10087
10088                         case 'ccsid1148':
10089                         case 'cp1148':
10090                         case 'ebcdicinternational500euro':
10091                         case 'ibm1148':
10092                                 return 'IBM01148';
10093
10094                         case 'ccsid1149':
10095                         case 'cp1149':
10096                         case 'ebcdicis871euro':
10097                         case 'ibm1149':
10098                                 return 'IBM01149';
10099
10100                         case 'csiso143iecp271':
10101                         case 'iecp271':
10102                         case 'isoir143':
10103                                 return 'IEC_P27-1';
10104
10105                         case 'csiso49inis':
10106                         case 'inis':
10107                         case 'isoir49':
10108                                 return 'INIS';
10109
10110                         case 'csiso50inis8':
10111                         case 'inis8':
10112                         case 'isoir50':
10113                                 return 'INIS-8';
10114
10115                         case 'csiso51iniscyrillic':
10116                         case 'iniscyrillic':
10117                         case 'isoir51':
10118                                 return 'INIS-cyrillic';
10119
10120                         case 'csinvariant':
10121                         case 'invariant':
10122                                 return 'INVARIANT';
10123
10124                         case 'iso2022cn':
10125                                 return 'ISO-2022-CN';
10126
10127                         case 'iso2022cnext':
10128                                 return 'ISO-2022-CN-EXT';
10129
10130                         case 'csiso2022jp':
10131                         case 'iso2022jp':
10132                                 return 'ISO-2022-JP';
10133
10134                         case 'csiso2022jp2':
10135                         case 'iso2022jp2':
10136                                 return 'ISO-2022-JP-2';
10137
10138                         case 'csiso2022kr':
10139                         case 'iso2022kr':
10140                                 return 'ISO-2022-KR';
10141
10142                         case 'cswindows30latin1':
10143                         case 'iso88591windows30latin1':
10144                                 return 'ISO-8859-1-Windows-3.0-Latin-1';
10145
10146                         case 'cswindows31latin1':
10147                         case 'iso88591windows31latin1':
10148                                 return 'ISO-8859-1-Windows-3.1-Latin-1';
10149
10150                         case 'csisolatin2':
10151                         case 'iso88592':
10152                         case 'iso885921987':
10153                         case 'isoir101':
10154                         case 'l2':
10155                         case 'latin2':
10156                                 return 'ISO-8859-2';
10157
10158                         case 'cswindows31latin2':
10159                         case 'iso88592windowslatin2':
10160                                 return 'ISO-8859-2-Windows-Latin-2';
10161
10162                         case 'csisolatin3':
10163                         case 'iso88593':
10164                         case 'iso885931988':
10165                         case 'isoir109':
10166                         case 'l3':
10167                         case 'latin3':
10168                                 return 'ISO-8859-3';
10169
10170                         case 'csisolatin4':
10171                         case 'iso88594':
10172                         case 'iso885941988':
10173                         case 'isoir110':
10174                         case 'l4':
10175                         case 'latin4':
10176                                 return 'ISO-8859-4';
10177
10178                         case 'csisolatincyrillic':
10179                         case 'cyrillic':
10180                         case 'iso88595':
10181                         case 'iso885951988':
10182                         case 'isoir144':
10183                                 return 'ISO-8859-5';
10184
10185                         case 'arabic':
10186                         case 'asmo708':
10187                         case 'csisolatinarabic':
10188                         case 'ecma114':
10189                         case 'iso88596':
10190                         case 'iso885961987':
10191                         case 'isoir127':
10192                                 return 'ISO-8859-6';
10193
10194                         case 'csiso88596e':
10195                         case 'iso88596e':
10196                                 return 'ISO-8859-6-E';
10197
10198                         case 'csiso88596i':
10199                         case 'iso88596i':
10200                                 return 'ISO-8859-6-I';
10201
10202                         case 'csisolatingreek':
10203                         case 'ecma118':
10204                         case 'elot928':
10205                         case 'greek':
10206                         case 'greek8':
10207                         case 'iso88597':
10208                         case 'iso885971987':
10209                         case 'isoir126':
10210                                 return 'ISO-8859-7';
10211
10212                         case 'csisolatinhebrew':
10213                         case 'hebrew':
10214                         case 'iso88598':
10215                         case 'iso885981988':
10216                         case 'isoir138':
10217                                 return 'ISO-8859-8';
10218
10219                         case 'csiso88598e':
10220                         case 'iso88598e':
10221                                 return 'ISO-8859-8-E';
10222
10223                         case 'csiso88598i':
10224                         case 'iso88598i':
10225                                 return 'ISO-8859-8-I';
10226
10227                         case 'cswindows31latin5':
10228                         case 'iso88599windowslatin5':
10229                                 return 'ISO-8859-9-Windows-Latin-5';
10230
10231                         case 'csisolatin6':
10232                         case 'iso885910':
10233                         case 'iso8859101992':
10234                         case 'isoir157':
10235                         case 'l6':
10236                         case 'latin6':
10237                                 return 'ISO-8859-10';
10238
10239                         case 'iso885913':
10240                                 return 'ISO-8859-13';
10241
10242                         case 'iso885914':
10243                         case 'iso8859141998':
10244                         case 'isoceltic':
10245                         case 'isoir199':
10246                         case 'l8':
10247                         case 'latin8':
10248                                 return 'ISO-8859-14';
10249
10250                         case 'iso885915':
10251                         case 'latin9':
10252                                 return 'ISO-8859-15';
10253
10254                         case 'iso885916':
10255                         case 'iso8859162001':
10256                         case 'isoir226':
10257                         case 'l10':
10258                         case 'latin10':
10259                                 return 'ISO-8859-16';
10260
10261                         case 'iso10646j1':
10262                                 return 'ISO-10646-J-1';
10263
10264                         case 'csunicode':
10265                         case 'iso10646ucs2':
10266                                 return 'ISO-10646-UCS-2';
10267
10268                         case 'csucs4':
10269                         case 'iso10646ucs4':
10270                                 return 'ISO-10646-UCS-4';
10271
10272                         case 'csunicodeascii':
10273                         case 'iso10646ucsbasic':
10274                                 return 'ISO-10646-UCS-Basic';
10275
10276                         case 'csunicodelatin1':
10277                         case 'iso10646':
10278                         case 'iso10646unicodelatin1':
10279                                 return 'ISO-10646-Unicode-Latin1';
10280
10281                         case 'csiso10646utf1':
10282                         case 'iso10646utf1':
10283                                 return 'ISO-10646-UTF-1';
10284
10285                         case 'csiso115481':
10286                         case 'iso115481':
10287                         case 'isotr115481':
10288                                 return 'ISO-11548-1';
10289
10290                         case 'csiso90':
10291                         case 'isoir90':
10292                                 return 'iso-ir-90';
10293
10294                         case 'csunicodeibm1261':
10295                         case 'isounicodeibm1261':
10296                                 return 'ISO-Unicode-IBM-1261';
10297
10298                         case 'csunicodeibm1264':
10299                         case 'isounicodeibm1264':
10300                                 return 'ISO-Unicode-IBM-1264';
10301
10302                         case 'csunicodeibm1265':
10303                         case 'isounicodeibm1265':
10304                                 return 'ISO-Unicode-IBM-1265';
10305
10306                         case 'csunicodeibm1268':
10307                         case 'isounicodeibm1268':
10308                                 return 'ISO-Unicode-IBM-1268';
10309
10310                         case 'csunicodeibm1276':
10311                         case 'isounicodeibm1276':
10312                                 return 'ISO-Unicode-IBM-1276';
10313
10314                         case 'csiso646basic1983':
10315                         case 'iso646basic1983':
10316                         case 'ref':
10317                                 return 'ISO_646.basic:1983';
10318
10319                         case 'csiso2intlrefversion':
10320                         case 'irv':
10321                         case 'iso646irv1983':
10322                         case 'isoir2':
10323                                 return 'ISO_646.irv:1983';
10324
10325                         case 'csiso2033':
10326                         case 'e13b':
10327                         case 'iso20331983':
10328                         case 'isoir98':
10329                                 return 'ISO_2033-1983';
10330
10331                         case 'csiso5427cyrillic':
10332                         case 'iso5427':
10333                         case 'isoir37':
10334                                 return 'ISO_5427';
10335
10336                         case 'iso5427cyrillic1981':
10337                         case 'iso54271981':
10338                         case 'isoir54':
10339                                 return 'ISO_5427:1981';
10340
10341                         case 'csiso5428greek':
10342                         case 'iso54281980':
10343                         case 'isoir55':
10344                                 return 'ISO_5428:1980';
10345
10346                         case 'csiso6937add':
10347                         case 'iso6937225':
10348                         case 'isoir152':
10349                                 return 'ISO_6937-2-25';
10350
10351                         case 'csisotextcomm':
10352                         case 'iso69372add':
10353                         case 'isoir142':
10354                                 return 'ISO_6937-2-add';
10355
10356                         case 'csiso8859supp':
10357                         case 'iso8859supp':
10358                         case 'isoir154':
10359                         case 'latin125':
10360                                 return 'ISO_8859-supp';
10361
10362                         case 'csiso10367box':
10363                         case 'iso10367box':
10364                         case 'isoir155':
10365                                 return 'ISO_10367-box';
10366
10367                         case 'csiso15italian':
10368                         case 'iso646it':
10369                         case 'isoir15':
10370                         case 'it':
10371                                 return 'IT';
10372
10373                         case 'csiso13jisc6220jp':
10374                         case 'isoir13':
10375                         case 'jisc62201969':
10376                         case 'jisc62201969jp':
10377                         case 'katakana':
10378                         case 'x2017':
10379                                 return 'JIS_C6220-1969-jp';
10380
10381                         case 'csiso14jisc6220ro':
10382                         case 'iso646jp':
10383                         case 'isoir14':
10384                         case 'jisc62201969ro':
10385                         case 'jp':
10386                                 return 'JIS_C6220-1969-ro';
10387
10388                         case 'csiso42jisc62261978':
10389                         case 'isoir42':
10390                         case 'jisc62261978':
10391                                 return 'JIS_C6226-1978';
10392
10393                         case 'csiso87jisx208':
10394                         case 'isoir87':
10395                         case 'jisc62261983':
10396                         case 'jisx2081983':
10397                         case 'x208':
10398                                 return 'JIS_C6226-1983';
10399
10400                         case 'csiso91jisc62291984a':
10401                         case 'isoir91':
10402                         case 'jisc62291984a':
10403                         case 'jpocra':
10404                                 return 'JIS_C6229-1984-a';
10405
10406                         case 'csiso92jisc62991984b':
10407                         case 'iso646jpocrb':
10408                         case 'isoir92':
10409                         case 'jisc62291984b':
10410                         case 'jpocrb':
10411                                 return 'JIS_C6229-1984-b';
10412
10413                         case 'csiso93jis62291984badd':
10414                         case 'isoir93':
10415                         case 'jisc62291984badd':
10416                         case 'jpocrbadd':
10417                                 return 'JIS_C6229-1984-b-add';
10418
10419                         case 'csiso94jis62291984hand':
10420                         case 'isoir94':
10421                         case 'jisc62291984hand':
10422                         case 'jpocrhand':
10423                                 return 'JIS_C6229-1984-hand';
10424
10425                         case 'csiso95jis62291984handadd':
10426                         case 'isoir95':
10427                         case 'jisc62291984handadd':
10428                         case 'jpocrhandadd':
10429                                 return 'JIS_C6229-1984-hand-add';
10430
10431                         case 'csiso96jisc62291984kana':
10432                         case 'isoir96':
10433                         case 'jisc62291984kana':
10434                                 return 'JIS_C6229-1984-kana';
10435
10436                         case 'csjisencoding':
10437                         case 'jisencoding':
10438                                 return 'JIS_Encoding';
10439
10440                         case 'cshalfwidthkatakana':
10441                         case 'jisx201':
10442                         case 'x201':
10443                                 return 'JIS_X0201';
10444
10445                         case 'csiso159jisx2121990':
10446                         case 'isoir159':
10447                         case 'jisx2121990':
10448                         case 'x212':
10449                                 return 'JIS_X0212-1990';
10450
10451                         case 'csiso141jusib1002':
10452                         case 'iso646yu':
10453                         case 'isoir141':
10454                         case 'js':
10455                         case 'jusib1002':
10456                         case 'yu':
10457                                 return 'JUS_I.B1.002';
10458
10459                         case 'csiso147macedonian':
10460                         case 'isoir147':
10461                         case 'jusib1003mac':
10462                         case 'macedonian':
10463                                 return 'JUS_I.B1.003-mac';
10464
10465                         case 'csiso146serbian':
10466                         case 'isoir146':
10467                         case 'jusib1003serb':
10468                         case 'serbian':
10469                                 return 'JUS_I.B1.003-serb';
10470
10471                         case 'koi7switched':
10472                                 return 'KOI7-switched';
10473
10474                         case 'cskoi8r':
10475                         case 'koi8r':
10476                                 return 'KOI8-R';
10477
10478                         case 'koi8u':
10479                                 return 'KOI8-U';
10480
10481                         case 'csksc5636':
10482                         case 'iso646kr':
10483                         case 'ksc5636':
10484                                 return 'KSC5636';
10485
10486                         case 'cskz1048':
10487                         case 'kz1048':
10488                         case 'rk1048':
10489                         case 'strk10482002':
10490                                 return 'KZ-1048';
10491
10492                         case 'csiso19latingreek':
10493                         case 'isoir19':
10494                         case 'latingreek':
10495                                 return 'latin-greek';
10496
10497                         case 'csiso27latingreek1':
10498                         case 'isoir27':
10499                         case 'latingreek1':
10500                                 return 'Latin-greek-1';
10501
10502                         case 'csiso158lap':
10503                         case 'isoir158':
10504                         case 'lap':
10505                         case 'latinlap':
10506                                 return 'latin-lap';
10507
10508                         case 'csmacintosh':
10509                         case 'mac':
10510                         case 'macintosh':
10511                                 return 'macintosh';
10512
10513                         case 'csmicrosoftpublishing':
10514                         case 'microsoftpublishing':
10515                                 return 'Microsoft-Publishing';
10516
10517                         case 'csmnem':
10518                         case 'mnem':
10519                                 return 'MNEM';
10520
10521                         case 'csmnemonic':
10522                         case 'mnemonic':
10523                                 return 'MNEMONIC';
10524
10525                         case 'csiso86hungarian':
10526                         case 'hu':
10527                         case 'iso646hu':
10528                         case 'isoir86':
10529                         case 'msz77953':
10530                                 return 'MSZ_7795.3';
10531
10532                         case 'csnatsdano':
10533                         case 'isoir91':
10534                         case 'natsdano':
10535                                 return 'NATS-DANO';
10536
10537                         case 'csnatsdanoadd':
10538                         case 'isoir92':
10539                         case 'natsdanoadd':
10540                                 return 'NATS-DANO-ADD';
10541
10542                         case 'csnatssefi':
10543                         case 'isoir81':
10544                         case 'natssefi':
10545                                 return 'NATS-SEFI';
10546
10547                         case 'csnatssefiadd':
10548                         case 'isoir82':
10549                         case 'natssefiadd':
10550                                 return 'NATS-SEFI-ADD';
10551
10552                         case 'csiso151cuba':
10553                         case 'cuba':
10554                         case 'iso646cu':
10555                         case 'isoir151':
10556                         case 'ncnc1081':
10557                                 return 'NC_NC00-10:81';
10558
10559                         case 'csiso69french':
10560                         case 'fr':
10561                         case 'iso646fr':
10562                         case 'isoir69':
10563                         case 'nfz62010':
10564                                 return 'NF_Z_62-010';
10565
10566                         case 'csiso25french':
10567                         case 'iso646fr1':
10568                         case 'isoir25':
10569                         case 'nfz620101973':
10570                                 return 'NF_Z_62-010_(1973)';
10571
10572                         case 'csiso60danishnorwegian':
10573                         case 'csiso60norwegian1':
10574                         case 'iso646no':
10575                         case 'isoir60':
10576                         case 'no':
10577                         case 'ns45511':
10578                                 return 'NS_4551-1';
10579
10580                         case 'csiso61norwegian2':
10581                         case 'iso646no2':
10582                         case 'isoir61':
10583                         case 'no2':
10584                         case 'ns45512':
10585                                 return 'NS_4551-2';
10586
10587                         case 'osdebcdicdf3irv':
10588                                 return 'OSD_EBCDIC_DF03_IRV';
10589
10590                         case 'osdebcdicdf41':
10591                                 return 'OSD_EBCDIC_DF04_1';
10592
10593                         case 'osdebcdicdf415':
10594                                 return 'OSD_EBCDIC_DF04_15';
10595
10596                         case 'cspc8danishnorwegian':
10597                         case 'pc8danishnorwegian':
10598                                 return 'PC8-Danish-Norwegian';
10599
10600                         case 'cspc8turkish':
10601                         case 'pc8turkish':
10602                                 return 'PC8-Turkish';
10603
10604                         case 'csiso16portuguese':
10605                         case 'iso646pt':
10606                         case 'isoir16':
10607                         case 'pt':
10608                                 return 'PT';
10609
10610                         case 'csiso84portuguese2':
10611                         case 'iso646pt2':
10612                         case 'isoir84':
10613                         case 'pt2':
10614                                 return 'PT2';
10615
10616                         case 'cp154':
10617                         case 'csptcp154':
10618                         case 'cyrillicasian':
10619                         case 'pt154':
10620                         case 'ptcp154':
10621                                 return 'PTCP154';
10622
10623                         case 'scsu':
10624                                 return 'SCSU';
10625
10626                         case 'csiso10swedish':
10627                         case 'fi':
10628                         case 'iso646fi':
10629                         case 'iso646se':
10630                         case 'isoir10':
10631                         case 'se':
10632                         case 'sen850200b':
10633                                 return 'SEN_850200_B';
10634
10635                         case 'csiso11swedishfornames':
10636                         case 'iso646se2':
10637                         case 'isoir11':
10638                         case 'se2':
10639                         case 'sen850200c':
10640                                 return 'SEN_850200_C';
10641
10642                         case 'csiso102t617bit':
10643                         case 'isoir102':
10644                         case 't617bit':
10645                                 return 'T.61-7bit';
10646
10647                         case 'csiso103t618bit':
10648                         case 'isoir103':
10649                         case 't61':
10650                         case 't618bit':
10651                                 return 'T.61-8bit';
10652
10653                         case 'csiso128t101g2':
10654                         case 'isoir128':
10655                         case 't101g2':
10656                                 return 'T.101-G2';
10657
10658                         case 'cstscii':
10659                         case 'tscii':
10660                                 return 'TSCII';
10661
10662                         case 'csunicode11':
10663                         case 'unicode11':
10664                                 return 'UNICODE-1-1';
10665
10666                         case 'csunicode11utf7':
10667                         case 'unicode11utf7':
10668                                 return 'UNICODE-1-1-UTF-7';
10669
10670                         case 'csunknown8bit':
10671                         case 'unknown8bit':
10672                                 return 'UNKNOWN-8BIT';
10673
10674                         case 'ansix341968':
10675                         case 'ansix341986':
10676                         case 'ascii':
10677                         case 'cp367':
10678                         case 'csascii':
10679                         case 'ibm367':
10680                         case 'iso646irv1991':
10681                         case 'iso646us':
10682                         case 'isoir6':
10683                         case 'us':
10684                         case 'usascii':
10685                                 return 'US-ASCII';
10686
10687                         case 'csusdk':
10688                         case 'usdk':
10689                                 return 'us-dk';
10690
10691                         case 'utf7':
10692                                 return 'UTF-7';
10693
10694                         case 'utf8':
10695                                 return 'UTF-8';
10696
10697                         case 'utf16':
10698                                 return 'UTF-16';
10699
10700                         case 'utf16be':
10701                                 return 'UTF-16BE';
10702
10703                         case 'utf16le':
10704                                 return 'UTF-16LE';
10705
10706                         case 'utf32':
10707                                 return 'UTF-32';
10708
10709                         case 'utf32be':
10710                                 return 'UTF-32BE';
10711
10712                         case 'utf32le':
10713                                 return 'UTF-32LE';
10714
10715                         case 'csventurainternational':
10716                         case 'venturainternational':
10717                                 return 'Ventura-International';
10718
10719                         case 'csventuramath':
10720                         case 'venturamath':
10721                                 return 'Ventura-Math';
10722
10723                         case 'csventuraus':
10724                         case 'venturaus':
10725                                 return 'Ventura-US';
10726
10727                         case 'csiso70videotexsupp1':
10728                         case 'isoir70':
10729                         case 'videotexsuppl':
10730                                 return 'videotex-suppl';
10731
10732                         case 'csviqr':
10733                         case 'viqr':
10734                                 return 'VIQR';
10735
10736                         case 'csviscii':
10737                         case 'viscii':
10738                                 return 'VISCII';
10739
10740                         case 'csshiftjis':
10741                         case 'cswindows31j':
10742                         case 'mskanji':
10743                         case 'shiftjis':
10744                         case 'windows31j':
10745                                 return 'Windows-31J';
10746
10747                         case 'iso885911':
10748                         case 'tis620':
10749                                 return 'windows-874';
10750
10751                         case 'cseuckr':
10752                         case 'csksc56011987':
10753                         case 'euckr':
10754                         case 'isoir149':
10755                         case 'korean':
10756                         case 'ksc5601':
10757                         case 'ksc56011987':
10758                         case 'ksc56011989':
10759                         case 'windows949':
10760                                 return 'windows-949';
10761
10762                         case 'windows1250':
10763                                 return 'windows-1250';
10764
10765                         case 'windows1251':
10766                                 return 'windows-1251';
10767
10768                         case 'cp819':
10769                         case 'csisolatin1':
10770                         case 'ibm819':
10771                         case 'iso88591':
10772                         case 'iso885911987':
10773                         case 'isoir100':
10774                         case 'l1':
10775                         case 'latin1':
10776                         case 'windows1252':
10777                                 return 'windows-1252';
10778
10779                         case 'windows1253':
10780                                 return 'windows-1253';
10781
10782                         case 'csisolatin5':
10783                         case 'iso88599':
10784                         case 'iso885991989':
10785                         case 'isoir148':
10786                         case 'l5':
10787                         case 'latin5':
10788                         case 'windows1254':
10789                                 return 'windows-1254';
10790
10791                         case 'windows1255':
10792                                 return 'windows-1255';
10793
10794                         case 'windows1256':
10795                                 return 'windows-1256';
10796
10797                         case 'windows1257':
10798                                 return 'windows-1257';
10799
10800                         case 'windows1258':
10801                                 return 'windows-1258';
10802
10803                         default:
10804                                 return $charset;
10805                 }
10806         }
10807
10808         function get_curl_version()
10809         {
10810                 if (is_array($curl = curl_version()))
10811                 {
10812                         $curl = $curl['version'];
10813                 }
10814                 elseif (substr($curl, 0, 5) === 'curl/')
10815                 {
10816                         $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
10817                 }
10818                 elseif (substr($curl, 0, 8) === 'libcurl/')
10819                 {
10820                         $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
10821                 }
10822                 else
10823                 {
10824                         $curl = 0;
10825                 }
10826                 return $curl;
10827         }
10828
10829         function is_subclass_of($class1, $class2)
10830         {
10831                 if (func_num_args() !== 2)
10832                 {
10833                         trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING);
10834                 }
10835                 elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1))
10836                 {
10837                         return is_subclass_of($class1, $class2);
10838                 }
10839                 elseif (is_string($class1) && is_string($class2))
10840                 {
10841                         if (class_exists($class1))
10842                         {
10843                                 if (class_exists($class2))
10844                                 {
10845                                         $class2 = strtolower($class2);
10846                                         while ($class1 = strtolower(get_parent_class($class1)))
10847                                         {
10848                                                 if ($class1 === $class2)
10849                                                 {
10850                                                         return true;
10851                                                 }
10852                                         }
10853                                 }
10854                         }
10855                         else
10856                         {
10857                                 trigger_error('Unknown class passed as parameter', E_USER_WARNNG);
10858                         }
10859                 }
10860                 return false;
10861         }
10862
10863         /**
10864          * Strip HTML comments
10865          *
10866          * @access public
10867          * @param string $data Data to strip comments from
10868          * @return string Comment stripped string
10869          */
10870         function strip_comments($data)
10871         {
10872                 $output = '';
10873                 while (($start = strpos($data, '<!--')) !== false)
10874                 {
10875                         $output .= substr($data, 0, $start);
10876                         if (($end = strpos($data, '-->', $start)) !== false)
10877                         {
10878                                 $data = substr_replace($data, '', 0, $end + 3);
10879                         }
10880                         else
10881                         {
10882                                 $data = '';
10883                         }
10884                 }
10885                 return $output . $data;
10886         }
10887
10888         function parse_date($dt)
10889         {
10890                 $parser = SimplePie_Parse_Date::get();
10891                 return $parser->parse($dt);
10892         }
10893
10894         /**
10895          * Decode HTML entities
10896          *
10897          * @static
10898          * @access public
10899          * @param string $data Input data
10900          * @return string Output data
10901          */
10902         function entities_decode($data)
10903         {
10904                 $decoder =& new SimplePie_Decode_HTML_Entities($data);
10905                 return $decoder->parse();
10906         }
10907
10908         /**
10909          * Remove RFC822 comments
10910          *
10911          * @access public
10912          * @param string $data Data to strip comments from
10913          * @return string Comment stripped string
10914          */
10915         function uncomment_rfc822($string)
10916         {
10917                 $string = (string) $string;
10918                 $position = 0;
10919                 $length = strlen($string);
10920                 $depth = 0;
10921
10922                 $output = '';
10923
10924                 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
10925                 {
10926                         $output .= substr($string, $position, $pos - $position);
10927                         $position = $pos + 1;
10928                         if ($string[$pos - 1] !== '\\')
10929                         {
10930                                 $depth++;
10931                                 while ($depth && $position < $length)
10932                                 {
10933                                         $position += strcspn($string, '()', $position);
10934                                         if ($string[$position - 1] === '\\')
10935                                         {
10936                                                 $position++;
10937                                                 continue;
10938                                         }
10939                                         elseif (isset($string[$position]))
10940                                         {
10941                                                 switch ($string[$position])
10942                                                 {
10943                                                         case '(':
10944                                                                 $depth++;
10945                                                                 break;
10946
10947                                                         case ')':
10948                                                                 $depth--;
10949                                                                 break;
10950                                                 }
10951                                                 $position++;
10952                                         }
10953                                         else
10954                                         {
10955                                                 break;
10956                                         }
10957                                 }
10958                         }
10959                         else
10960                         {
10961                                 $output .= '(';
10962                         }
10963                 }
10964                 $output .= substr($string, $position);
10965
10966                 return $output;
10967         }
10968
10969         function parse_mime($mime)
10970         {
10971                 if (($pos = strpos($mime, ';')) === false)
10972                 {
10973                         return trim($mime);
10974                 }
10975                 else
10976                 {
10977                         return trim(substr($mime, 0, $pos));
10978                 }
10979         }
10980
10981         function htmlspecialchars_decode($string, $quote_style)
10982         {
10983                 if (function_exists('htmlspecialchars_decode'))
10984                 {
10985                         return htmlspecialchars_decode($string, $quote_style);
10986                 }
10987                 else
10988                 {
10989                         return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
10990                 }
10991         }
10992
10993         function atom_03_construct_type($attribs)
10994         {
10995                 if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
10996                 {
10997                         $mode = SIMPLEPIE_CONSTRUCT_BASE64;
10998                 }
10999                 else
11000                 {
11001                         $mode = SIMPLEPIE_CONSTRUCT_NONE;
11002                 }
11003                 if (isset($attribs['']['type']))
11004                 {
11005                         switch (strtolower(trim($attribs['']['type'])))
11006                         {
11007                                 case 'text':
11008                                 case 'text/plain':
11009                                         return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
11010
11011                                 case 'html':
11012                                 case 'text/html':
11013                                         return SIMPLEPIE_CONSTRUCT_HTML | $mode;
11014
11015                                 case 'xhtml':
11016                                 case 'application/xhtml+xml':
11017                                         return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
11018
11019                                 default:
11020                                         return SIMPLEPIE_CONSTRUCT_NONE | $mode;
11021                         }
11022                 }
11023                 else
11024                 {
11025                         return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
11026                 }
11027         }
11028
11029         function atom_10_construct_type($attribs)
11030         {
11031                 if (isset($attribs['']['type']))
11032                 {
11033                         switch (strtolower(trim($attribs['']['type'])))
11034                         {
11035                                 case 'text':
11036                                         return SIMPLEPIE_CONSTRUCT_TEXT;
11037
11038                                 case 'html':
11039                                         return SIMPLEPIE_CONSTRUCT_HTML;
11040
11041                                 case 'xhtml':
11042                                         return SIMPLEPIE_CONSTRUCT_XHTML;
11043
11044                                 default:
11045                                         return SIMPLEPIE_CONSTRUCT_NONE;
11046                         }
11047                 }
11048                 return SIMPLEPIE_CONSTRUCT_TEXT;
11049         }
11050
11051         function atom_10_content_construct_type($attribs)
11052         {
11053                 if (isset($attribs['']['type']))
11054                 {
11055                         $type = strtolower(trim($attribs['']['type']));
11056                         switch ($type)
11057                         {
11058                                 case 'text':
11059                                         return SIMPLEPIE_CONSTRUCT_TEXT;
11060
11061                                 case 'html':
11062                                         return SIMPLEPIE_CONSTRUCT_HTML;
11063
11064                                 case 'xhtml':
11065                                         return SIMPLEPIE_CONSTRUCT_XHTML;
11066                         }
11067                         if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
11068                         {
11069                                 return SIMPLEPIE_CONSTRUCT_NONE;
11070                         }
11071                         else
11072                         {
11073                                 return SIMPLEPIE_CONSTRUCT_BASE64;
11074                         }
11075                 }
11076                 else
11077                 {
11078                         return SIMPLEPIE_CONSTRUCT_TEXT;
11079                 }
11080         }
11081
11082         function is_isegment_nz_nc($string)
11083         {
11084                 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);
11085         }
11086
11087         function space_seperated_tokens($string)
11088         {
11089                 $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
11090                 $string_length = strlen($string);
11091
11092                 $position = strspn($string, $space_characters);
11093                 $tokens = array();
11094
11095                 while ($position < $string_length)
11096                 {
11097                         $len = strcspn($string, $space_characters, $position);
11098                         $tokens[] = substr($string, $position, $len);
11099                         $position += $len;
11100                         $position += strspn($string, $space_characters, $position);
11101                 }
11102
11103                 return $tokens;
11104         }
11105
11106         function array_unique($array)
11107         {
11108                 if (version_compare(PHP_VERSION, '5.2', '>='))
11109                 {
11110                         return array_unique($array);
11111                 }
11112                 else
11113                 {
11114                         $array = (array) $array;
11115                         $new_array = array();
11116                         $new_array_strings = array();
11117                         foreach ($array as $key => $value)
11118                         {
11119                                 if (is_object($value))
11120                                 {
11121                                         if (method_exists($value, '__toString'))
11122                                         {
11123                                                 $cmp = $value->__toString();
11124                                         }
11125                                         else
11126                                         {
11127                                                 trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR);
11128                                         }
11129                                 }
11130                                 elseif (is_array($value))
11131                                 {
11132                                         $cmp = (string) reset($value);
11133                                 }
11134                                 else
11135                                 {
11136                                         $cmp = (string) $value;
11137                                 }
11138                                 if (!in_array($cmp, $new_array_strings))
11139                                 {
11140                                         $new_array[$key] = $value;
11141                                         $new_array_strings[] = $cmp;
11142                                 }
11143                         }
11144                         return $new_array;
11145                 }
11146         }
11147
11148         /**
11149          * Converts a unicode codepoint to a UTF-8 character
11150          *
11151          * @static
11152          * @access public
11153          * @param int $codepoint Unicode codepoint
11154          * @return string UTF-8 character
11155          */
11156         function codepoint_to_utf8($codepoint)
11157         {
11158                 $codepoint = (int) $codepoint;
11159                 if ($codepoint < 0)
11160                 {
11161                         return false;
11162                 }
11163                 else if ($codepoint <= 0x7f)
11164                 {
11165                         return chr($codepoint);
11166                 }
11167                 else if ($codepoint <= 0x7ff)
11168                 {
11169                         return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
11170                 }
11171                 else if ($codepoint <= 0xffff)
11172                 {
11173                         return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
11174                 }
11175                 else if ($codepoint <= 0x10ffff)
11176                 {
11177                         return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
11178                 }
11179                 else
11180                 {
11181                         // U+FFFD REPLACEMENT CHARACTER
11182                         return "\xEF\xBF\xBD";
11183                 }
11184         }
11185
11186         /**
11187          * Re-implementation of PHP 5's stripos()
11188          *
11189          * Returns the numeric position of the first occurrence of needle in the
11190          * haystack string.
11191          *
11192          * @static
11193          * @access string
11194          * @param object $haystack
11195          * @param string $needle Note that the needle may be a string of one or more
11196          *     characters. If needle is not a string, it is converted to an integer
11197          *     and applied as the ordinal value of a character.
11198          * @param int $offset The optional offset parameter allows you to specify which
11199          *     character in haystack to start searching. The position returned is still
11200          *     relative to the beginning of haystack.
11201          * @return bool If needle is not found, stripos() will return boolean false.
11202          */
11203         function stripos($haystack, $needle, $offset = 0)
11204         {
11205                 if (function_exists('stripos'))
11206                 {
11207                         return stripos($haystack, $needle, $offset);
11208                 }
11209                 else
11210                 {
11211                         if (is_string($needle))
11212                         {
11213                                 $needle = strtolower($needle);
11214                         }
11215                         elseif (is_int($needle) || is_bool($needle) || is_double($needle))
11216                         {
11217                                 $needle = strtolower(chr($needle));
11218                         }
11219                         else
11220                         {
11221                                 trigger_error('needle is not a string or an integer', E_USER_WARNING);
11222                                 return false;
11223                         }
11224
11225                         return strpos(strtolower($haystack), $needle, $offset);
11226                 }
11227         }
11228
11229         /**
11230          * Similar to parse_str()
11231          *
11232          * Returns an associative array of name/value pairs, where the value is an
11233          * array of values that have used the same name
11234          *
11235          * @static
11236          * @access string
11237          * @param string $str The input string.
11238          * @return array
11239          */
11240         function parse_str($str)
11241         {
11242                 $return = array();
11243                 $str = explode('&', $str);
11244
11245                 foreach ($str as $section)
11246                 {
11247                         if (strpos($section, '=') !== false)
11248                         {
11249                                 list($name, $value) = explode('=', $section, 2);
11250                                 $return[urldecode($name)][] = urldecode($value);
11251                         }
11252                         else
11253                         {
11254                                 $return[urldecode($section)][] = null;
11255                         }
11256                 }
11257
11258                 return $return;
11259         }
11260
11261         /**
11262          * Detect XML encoding, as per XML 1.0 Appendix F.1
11263          *
11264          * @todo Add support for EBCDIC
11265          * @param string $data XML data
11266          * @return array Possible encodings
11267          */
11268         function xml_encoding($data)
11269         {
11270                 // UTF-32 Big Endian BOM
11271                 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
11272                 {
11273                         $encoding[] = 'UTF-32BE';
11274                 }
11275                 // UTF-32 Little Endian BOM
11276                 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
11277                 {
11278                         $encoding[] = 'UTF-32LE';
11279                 }
11280                 // UTF-16 Big Endian BOM
11281                 elseif (substr($data, 0, 2) === "\xFE\xFF")
11282                 {
11283                         $encoding[] = 'UTF-16BE';
11284                 }
11285                 // UTF-16 Little Endian BOM
11286                 elseif (substr($data, 0, 2) === "\xFF\xFE")
11287                 {
11288                         $encoding[] = 'UTF-16LE';
11289                 }
11290                 // UTF-8 BOM
11291                 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
11292                 {
11293                         $encoding[] = 'UTF-8';
11294                 }
11295                 // UTF-32 Big Endian Without BOM
11296                 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")
11297                 {
11298                         if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
11299                         {
11300                                 $parser =& new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8'));
11301                                 if ($parser->parse())
11302                                 {
11303                                         $encoding[] = $parser->encoding;
11304                                 }
11305                         }
11306                         $encoding[] = 'UTF-32BE';
11307                 }
11308                 // UTF-32 Little Endian Without BOM
11309                 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")
11310                 {
11311                         if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
11312                         {
11313                                 $parser =& new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8'));
11314                                 if ($parser->parse())
11315                                 {
11316                                         $encoding[] = $parser->encoding;
11317                                 }
11318                         }
11319                         $encoding[] = 'UTF-32LE';
11320                 }
11321                 // UTF-16 Big Endian Without BOM
11322                 elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
11323                 {
11324                         if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
11325                         {
11326                                 $parser =& new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8'));
11327                                 if ($parser->parse())
11328                                 {
11329                                         $encoding[] = $parser->encoding;
11330                                 }
11331                         }
11332                         $encoding[] = 'UTF-16BE';
11333                 }
11334                 // UTF-16 Little Endian Without BOM
11335                 elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
11336                 {
11337                         if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
11338                         {
11339                                 $parser =& new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8'));
11340                                 if ($parser->parse())
11341                                 {
11342                                         $encoding[] = $parser->encoding;
11343                                 }
11344                         }
11345                         $encoding[] = 'UTF-16LE';
11346                 }
11347                 // US-ASCII (or superset)
11348                 elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
11349                 {
11350                         if ($pos = strpos($data, "\x3F\x3E"))
11351                         {
11352                                 $parser =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
11353                                 if ($parser->parse())
11354                                 {
11355                                         $encoding[] = $parser->encoding;
11356                                 }
11357                         }
11358                         $encoding[] = 'UTF-8';
11359                 }
11360                 // Fallback to UTF-8
11361                 else
11362                 {
11363                         $encoding[] = 'UTF-8';
11364                 }
11365                 return $encoding;
11366         }
11367
11368         function output_javascript()
11369         {
11370                 if (function_exists('ob_gzhandler'))
11371                 {
11372                         ob_start('ob_gzhandler');
11373                 }
11374                 header('Content-type: text/javascript; charset: UTF-8');
11375                 header('Cache-Control: must-revalidate');
11376                 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
11377                 ?>
11378 function embed_odeo(link) {
11379         document.writeln('<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url='+link+'"></embed>');
11380 }
11381
11382 function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
11383         if (placeholder != '') {
11384                 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>');
11385         }
11386         else {
11387                 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>');
11388         }
11389 }
11390
11391 function embed_flash(bgcolor, width, height, link, loop, type) {
11392         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>');
11393 }
11394
11395 function embed_flv(width, height, link, placeholder, loop, player) {
11396         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>');
11397 }
11398
11399 function embed_wmedia(width, height, link) {
11400         document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
11401 }
11402                 <?php
11403         }
11404
11405
11406
11407         /**
11408          * Format debugging information
11409          */
11410         function debug($sp)
11411         {
11412                 $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
11413                 $info .= 'PHP ' . PHP_VERSION . "\n";
11414                 if ($sp->error() !== null)
11415                 {
11416                         $info .= 'Error occurred: ' . $sp->error() . "\n";
11417                 }
11418                 else
11419                 {
11420                         $info .= "No error found.\n";
11421                 }
11422                 $info .= "Extensions:\n";
11423                 $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
11424                 foreach ($extensions as $ext)
11425                 {
11426                         if (extension_loaded($ext))
11427                         {
11428                                 $info .= "    $ext loaded\n";
11429                                 switch ($ext)
11430                                 {
11431                                         case 'pcre':
11432                                                 $info .= '      Version ' . PCRE_VERSION . "\n";
11433                                                 break;
11434                                         case 'curl':
11435                                                 $version = curl_version();
11436                                                 $info .= '      Version ' . $version['version'] . "\n";
11437                                                 break;
11438                                         case 'mbstring':
11439                                                 $info .= '      Overloading: ' . mb_get_info('func_overload') . "\n";
11440                                                 break;
11441                                         case 'iconv':
11442                                                 $info .= '      Version ' . ICONV_VERSION . "\n";
11443                                                 break;
11444                                         case 'xml':
11445                                                 $info .= '      Version ' . LIBXML_DOTTED_VERSION . "\n";
11446                                                 break;
11447                                 }
11448                         }
11449                         else
11450                         {
11451                                 $info .= "    $ext not loaded\n";
11452                         }
11453                 }
11454                 return $info;
11455         }
11456 }
11457
11458 /**
11459  * Decode HTML Entities
11460  *
11461  * This implements HTML5 as of revision 967 (2007-06-28)
11462  *
11463  * @package SimplePie
11464  */
11465 class SimplePie_Decode_HTML_Entities
11466 {
11467         /**
11468          * Data to be parsed
11469          *
11470          * @access private
11471          * @var string
11472          */
11473         var $data = '';
11474
11475         /**
11476          * Currently consumed bytes
11477          *
11478          * @access private
11479          * @var string
11480          */
11481         var $consumed = '';
11482
11483         /**
11484          * Position of the current byte being parsed
11485          *
11486          * @access private
11487          * @var int
11488          */
11489         var $position = 0;
11490
11491         /**
11492          * Create an instance of the class with the input data
11493          *
11494          * @access public
11495          * @param string $data Input data
11496          */
11497         function SimplePie_Decode_HTML_Entities($data)
11498         {
11499                 $this->data = $data;
11500         }
11501
11502         /**
11503          * Parse the input data
11504          *
11505          * @access public
11506          * @return string Output data
11507          */
11508         function parse()
11509         {
11510                 while (($this->position = strpos($this->data, '&', $this->position)) !== false)
11511                 {
11512                         $this->consume();
11513                         $this->entity();
11514                         $this->consumed = '';
11515                 }
11516                 return $this->data;
11517         }
11518
11519         /**
11520          * Consume the next byte
11521          *
11522          * @access private
11523          * @return mixed The next byte, or false, if there is no more data
11524          */
11525         function consume()
11526         {
11527                 if (isset($this->data[$this->position]))
11528                 {
11529                         $this->consumed .= $this->data[$this->position];
11530                         return $this->data[$this->position++];
11531                 }
11532                 else
11533                 {
11534                         return false;
11535                 }
11536         }
11537
11538         /**
11539          * Consume a range of characters
11540          *
11541          * @access private
11542          * @param string $chars Characters to consume
11543          * @return mixed A series of characters that match the range, or false
11544          */
11545         function consume_range($chars)
11546         {
11547                 if ($len = strspn($this->data, $chars, $this->position))
11548                 {
11549                         $data = substr($this->data, $this->position, $len);
11550                         $this->consumed .= $data;
11551                         $this->position += $len;
11552                         return $data;
11553                 }
11554                 else
11555                 {
11556                         return false;
11557                 }
11558         }
11559
11560         /**
11561          * Unconsume one byte
11562          *
11563          * @access private
11564          */
11565         function unconsume()
11566         {
11567                 $this->consumed = substr($this->consumed, 0, -1);
11568                 $this->position--;
11569         }
11570
11571         /**
11572          * Decode an entity
11573          *
11574          * @access private
11575          */
11576         function entity()
11577         {
11578                 switch ($this->consume())
11579                 {
11580                         case "\x09":
11581                         case "\x0A":
11582                         case "\x0B":
11583                         case "\x0B":
11584                         case "\x0C":
11585                         case "\x20":
11586                         case "\x3C":
11587                         case "\x26":
11588                         case false:
11589                                 break;
11590
11591                         case "\x23":
11592                                 switch ($this->consume())
11593                                 {
11594                                         case "\x78":
11595                                         case "\x58":
11596                                                 $range = '0123456789ABCDEFabcdef';
11597                                                 $hex = true;
11598                                                 break;
11599
11600                                         default:
11601                                                 $range = '0123456789';
11602                                                 $hex = false;
11603                                                 $this->unconsume();
11604                                                 break;
11605                                 }
11606
11607                                 if ($codepoint = $this->consume_range($range))
11608                                 {
11609                                         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");
11610
11611                                         if ($hex)
11612                                         {
11613                                                 $codepoint = hexdec($codepoint);
11614                                         }
11615                                         else
11616                                         {
11617                                                 $codepoint = intval($codepoint);
11618                                         }
11619
11620                                         if (isset($windows_1252_specials[$codepoint]))
11621                                         {
11622                                                 $replacement = $windows_1252_specials[$codepoint];
11623                                         }
11624                                         else
11625                                         {
11626                                                 $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
11627                                         }
11628
11629                                         if (!in_array($this->consume(), array(';', false), true))
11630                                         {
11631                                                 $this->unconsume();
11632                                         }
11633
11634                                         $consumed_length = strlen($this->consumed);
11635                                         $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
11636                                         $this->position += strlen($replacement) - $consumed_length;
11637                                 }
11638                                 break;
11639
11640                         default:
11641                                 static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C");
11642
11643                                 for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
11644                                 {
11645                                         $consumed = substr($this->consumed, 1);
11646                                         if (isset($entities[$consumed]))
11647                                         {
11648                                                 $match = $consumed;
11649                                         }
11650                                 }
11651
11652                                 if ($match !== null)
11653                                 {
11654                                         $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
11655                                         $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
11656                                 }
11657                                 break;
11658                 }
11659         }
11660 }
11661
11662 /**
11663  * IRI parser/serialiser
11664  *
11665  * @package SimplePie
11666  */
11667 class SimplePie_IRI
11668 {
11669         /**
11670          * Scheme
11671          *
11672          * @access private
11673          * @var string
11674          */
11675         var $scheme;
11676
11677         /**
11678          * User Information
11679          *
11680          * @access private
11681          * @var string
11682          */
11683         var $userinfo;
11684
11685         /**
11686          * Host
11687          *
11688          * @access private
11689          * @var string
11690          */
11691         var $host;
11692
11693         /**
11694          * Port
11695          *
11696          * @access private
11697          * @var string
11698          */
11699         var $port;
11700
11701         /**
11702          * Path
11703          *
11704          * @access private
11705          * @var string
11706          */
11707         var $path;
11708
11709         /**
11710          * Query
11711          *
11712          * @access private
11713          * @var string
11714          */
11715         var $query;
11716
11717         /**
11718          * Fragment
11719          *
11720          * @access private
11721          * @var string
11722          */
11723         var $fragment;
11724
11725         /**
11726          * Whether the object represents a valid IRI
11727          *
11728          * @access private
11729          * @var array
11730          */
11731         var $valid = array();
11732
11733         /**
11734          * Return the entire IRI when you try and read the object as a string
11735          *
11736          * @access public
11737          * @return string
11738          */
11739         function __toString()
11740         {
11741                 return $this->get_iri();
11742         }
11743
11744         /**
11745          * Create a new IRI object, from a specified string
11746          *
11747          * @access public
11748          * @param string $iri
11749          * @return SimplePie_IRI
11750          */
11751         function SimplePie_IRI($iri)
11752         {
11753                 $iri = (string) $iri;
11754                 if ($iri !== '')
11755                 {
11756                         $parsed = $this->parse_iri($iri);
11757                         $this->set_scheme($parsed['scheme']);
11758                         $this->set_authority($parsed['authority']);
11759                         $this->set_path($parsed['path']);
11760                         $this->set_query($parsed['query']);
11761                         $this->set_fragment($parsed['fragment']);
11762                 }
11763         }
11764
11765         /**
11766          * Create a new IRI object by resolving a relative IRI
11767          *
11768          * @static
11769          * @access public
11770          * @param SimplePie_IRI $base Base IRI
11771          * @param string $relative Relative IRI
11772          * @return SimplePie_IRI
11773          */
11774         function absolutize($base, $relative)
11775         {
11776                 $relative = (string) $relative;
11777                 if ($relative !== '')
11778                 {
11779                         $relative =& new SimplePie_IRI($relative);
11780                         if ($relative->get_scheme() !== null)
11781                         {
11782                                 $target = $relative;
11783                         }
11784                         elseif ($base->get_iri() !== null)
11785                         {
11786                                 if ($relative->get_authority() !== null)
11787                                 {
11788                                         $target = $relative;
11789                                         $target->set_scheme($base->get_scheme());
11790                                 }
11791                                 else
11792                                 {
11793                                         $target =& new SimplePie_IRI('');
11794                                         $target->set_scheme($base->get_scheme());
11795                                         $target->set_userinfo($base->get_userinfo());
11796                                         $target->set_host($base->get_host());
11797                                         $target->set_port($base->get_port());
11798                                         if ($relative->get_path() !== null)
11799                                         {
11800                                                 if (strpos($relative->get_path(), '/') === 0)
11801                                                 {
11802                                                         $target->set_path($relative->get_path());
11803                                                 }
11804                                                 elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null)
11805                                                 {
11806                                                         $target->set_path('/' . $relative->get_path());
11807                                                 }
11808                                                 elseif (($last_segment = strrpos($base->get_path(), '/')) !== false)
11809                                                 {
11810                                                         $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path());
11811                                                 }
11812                                                 else
11813                                                 {
11814                                                         $target->set_path($relative->get_path());
11815                                                 }
11816                                                 $target->set_query($relative->get_query());
11817                                         }
11818                                         else
11819                                         {
11820                                                 $target->set_path($base->get_path());
11821                                                 if ($relative->get_query() !== null)
11822                                                 {
11823                                                         $target->set_query($relative->get_query());
11824                                                 }
11825                                                 elseif ($base->get_query() !== null)
11826                                                 {
11827                                                         $target->set_query($base->get_query());
11828                                                 }
11829                                         }
11830                                 }
11831                                 $target->set_fragment($relative->get_fragment());
11832                         }
11833                         else
11834                         {
11835                                 // No base URL, just return the relative URL
11836                                 $target = $relative;
11837                         }
11838                 }
11839                 else
11840                 {
11841                         $target = $base;
11842                 }
11843                 return $target;
11844         }
11845
11846         /**
11847          * Parse an IRI into scheme/authority/path/query/fragment segments
11848          *
11849          * @access private
11850          * @param string $iri
11851          * @return array
11852          */
11853         function parse_iri($iri)
11854         {
11855                 preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match);
11856                 for ($i = count($match); $i <= 9; $i++)
11857                 {
11858                         $match[$i] = '';
11859                 }
11860                 return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]);
11861         }
11862
11863         /**
11864          * Remove dot segments from a path
11865          *
11866          * @access private
11867          * @param string $input
11868          * @return string
11869          */
11870         function remove_dot_segments($input)
11871         {
11872                 $output = '';
11873                 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
11874                 {
11875                         // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
11876                         if (strpos($input, '../') === 0)
11877                         {
11878                                 $input = substr($input, 3);
11879                         }
11880                         elseif (strpos($input, './') === 0)
11881                         {
11882                                 $input = substr($input, 2);
11883                         }
11884                         // 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,
11885                         elseif (strpos($input, '/./') === 0)
11886                         {
11887                                 $input = substr_replace($input, '/', 0, 3);
11888                         }
11889                         elseif ($input === '/.')
11890                         {
11891                                 $input = '/';
11892                         }
11893                         // 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,
11894                         elseif (strpos($input, '/../') === 0)
11895                         {
11896                                 $input = substr_replace($input, '/', 0, 4);
11897                                 $output = substr_replace($output, '', strrpos($output, '/'));
11898                         }
11899                         elseif ($input === '/..')
11900                         {
11901                                 $input = '/';
11902                                 $output = substr_replace($output, '', strrpos($output, '/'));
11903                         }
11904                         // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
11905                         elseif ($input === '.' || $input === '..')
11906                         {
11907                                 $input = '';
11908                         }
11909                         // 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
11910                         elseif (($pos = strpos($input, '/', 1)) !== false)
11911                         {
11912                                 $output .= substr($input, 0, $pos);
11913                                 $input = substr_replace($input, '', 0, $pos);
11914                         }
11915                         else
11916                         {
11917                                 $output .= $input;
11918                                 $input = '';
11919                         }
11920                 }
11921                 return $output . $input;
11922         }
11923
11924         /**
11925          * Replace invalid character with percent encoding
11926          *
11927          * @param string $string Input string
11928          * @param string $valid_chars Valid characters
11929          * @param int $case Normalise case
11930          * @return string
11931          */
11932         function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE, $iprivate = false)
11933         {
11934                 // Normalize as many pct-encoded sections as possible
11935                 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
11936
11937                 // Replace invalid percent characters
11938                 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
11939
11940                 // Add unreserved and % to $valid_chars (the latter is safe because all
11941                 // pct-encoded sections are now valid).
11942                 $valid_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
11943
11944                 // Now replace any bytes that aren't allowed with their pct-encoded versions
11945                 $position = 0;
11946                 $strlen = strlen($string);
11947                 while (($position += strspn($string, $valid_chars, $position)) < $strlen)
11948                 {
11949                         $value = ord($string[$position]);
11950
11951                         // Start position
11952                         $start = $position;
11953
11954                         // By default we are valid
11955                         $valid = true;
11956
11957                         // No one byte sequences are valid due to the while.
11958                         // Two byte sequence:
11959                         if (($value & 0xE0) === 0xC0)
11960                         {
11961                                 $character = ($value & 0x1F) << 6;
11962                                 $length = 2;
11963                                 $remaining = 1;
11964                         }
11965                         // Three byte sequence:
11966                         elseif (($value & 0xF0) === 0xE0)
11967                         {
11968                                 $character = ($value & 0x0F) << 12;
11969                                 $length = 3;
11970                                 $remaining = 2;
11971                         }
11972                         // Four byte sequence:
11973                         elseif (($value & 0xF8) === 0xF0)
11974                         {
11975                                 $character = ($value & 0x07) << 18;
11976                                 $length = 4;
11977                                 $remaining = 3;
11978                         }
11979                         // Invalid byte:
11980                         else
11981                         {
11982                                 $valid = false;
11983                                 $length = 1;
11984                                 $remaining = 0;
11985                         }
11986
11987                         if ($remaining)
11988                         {
11989                                 if ($position + $length <= $strlen)
11990                                 {
11991                                         for ($position++; $remaining; $position++)
11992                                         {
11993                                                 $value = ord($string[$position]);
11994
11995                                                 // Check that the byte is valid, then add it to the character:
11996                                                 if (($value & 0xC0) === 0x80)
11997                                                 {
11998                                                         $character |= ($value & 0x3F) << (--$remaining * 6);
11999                                                 }
12000                                                 // If it is invalid, count the sequence as invalid and reprocess the current byte:
12001                                                 else
12002                                                 {
12003                                                         $valid = false;
12004                                                         $position--;
12005                                                         break;
12006                                                 }
12007                                         }
12008                                 }
12009                                 else
12010                                 {
12011                                         $position = $strlen - 1;
12012                                         $valid = false;
12013                                 }
12014                         }
12015
12016                         // Percent encode anything invalid or not in ucschar
12017                         if (
12018                                 // Invalid sequences
12019                                 !$valid
12020                                 // Non-shortest form sequences are invalid
12021                                 || $length > 1 && $character <= 0x7F
12022                                 || $length > 2 && $character <= 0x7FF
12023                                 || $length > 3 && $character <= 0xFFFF
12024                                 // Outside of range of ucschar codepoints
12025                                 // Noncharacters
12026                                 || ($character & 0xFFFE) === 0xFFFE
12027                                 || $character >= 0xFDD0 && $character <= 0xFDEF
12028                                 || (
12029                                         // Everything else not in ucschar
12030                                            $character > 0xD7FF && $character < 0xF900
12031                                         || $character < 0xA0
12032                                         || $character > 0xEFFFD
12033                                 )
12034                                 && (
12035                                         // Everything not in iprivate, if it applies
12036                                            !$iprivate
12037                                         || $character < 0xE000
12038                                         || $character > 0x10FFFD
12039                                 )
12040                         )
12041                         {
12042                                 // If we were a character, pretend we weren't, but rather an error.
12043                                 if ($valid)
12044                                         $position--;
12045
12046                                 for ($j = $start; $j <= $position; $j++)
12047                                 {
12048                                         $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
12049                                         $j += 2;
12050                                         $position += 2;
12051                                         $strlen += 2;
12052                                 }
12053                         }
12054                 }
12055
12056                 // Normalise case
12057                 if ($case & SIMPLEPIE_LOWERCASE)
12058                 {
12059                         $string = strtolower($string);
12060                 }
12061                 elseif ($case & SIMPLEPIE_UPPERCASE)
12062                 {
12063                         $string = strtoupper($string);
12064                 }
12065
12066                 return $string;
12067         }
12068
12069         /**
12070          * Callback function for preg_replace_callback.
12071          *
12072          * Removes sequences of percent encoded bytes that represent UTF-8
12073          * encoded characters in iunreserved
12074          *
12075          * @access private
12076          * @param array $match PCRE match
12077          * @return string Replacement
12078          */
12079         function remove_iunreserved_percent_encoded($match)
12080         {
12081                 // As we just have valid percent encoded sequences we can just explode
12082                 // and ignore the first member of the returned array (an empty string).
12083                 $bytes = explode('%', $match[0]);
12084
12085                 // Initialize the new string (this is what will be returned) and that
12086                 // there are no bytes remaining in the current sequence (unsurprising
12087                 // at the first byte!).
12088                 $string = '';
12089                 $remaining = 0;
12090
12091                 // Loop over each and every byte, and set $value to its value
12092                 for ($i = 1, $len = count($bytes); $i < $len; $i++)
12093                 {
12094                         $value = hexdec($bytes[$i]);
12095
12096                         // If we're the first byte of sequence:
12097                         if (!$remaining)
12098                         {
12099                                 // Start position
12100                                 $start = $i;
12101
12102                                 // By default we are valid
12103                                 $valid = true;
12104
12105                                 // One byte sequence:
12106                                 if ($value <= 0x7F)
12107                                 {
12108                                         $character = $value;
12109                                         $length = 1;
12110                                 }
12111                                 // Two byte sequence:
12112                                 elseif (($value & 0xE0) === 0xC0)
12113                                 {
12114                                         $character = ($value & 0x1F) << 6;
12115                                         $length = 2;
12116                                         $remaining = 1;
12117                                 }
12118                                 // Three byte sequence:
12119                                 elseif (($value & 0xF0) === 0xE0)
12120                                 {
12121                                         $character = ($value & 0x0F) << 12;
12122                                         $length = 3;
12123                                         $remaining = 2;
12124                                 }
12125                                 // Four byte sequence:
12126                                 elseif (($value & 0xF8) === 0xF0)
12127                                 {
12128                                         $character = ($value & 0x07) << 18;
12129                                         $length = 4;
12130                                         $remaining = 3;
12131                                 }
12132                                 // Invalid byte:
12133                                 else
12134                                 {
12135                                         $valid = false;
12136                                         $remaining = 0;
12137                                 }
12138                         }
12139                         // Continuation byte:
12140                         else
12141                         {
12142                                 // Check that the byte is valid, then add it to the character:
12143                                 if (($value & 0xC0) === 0x80)
12144                                 {
12145                                         $remaining--;
12146                                         $character |= ($value & 0x3F) << ($remaining * 6);
12147                                 }
12148                                 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
12149                                 else
12150                                 {
12151                                         $valid = false;
12152                                         $remaining = 0;
12153                                         $i--;
12154                                 }
12155                         }
12156
12157                         // If we've reached the end of the current byte sequence, append it to Unicode::$data
12158                         if (!$remaining)
12159                         {
12160                                 // Percent encode anything invalid or not in iunreserved
12161                                 if (
12162                                         // Invalid sequences
12163                                         !$valid
12164                                         // Non-shortest form sequences are invalid
12165                                         || $length > 1 && $character <= 0x7F
12166                                         || $length > 2 && $character <= 0x7FF
12167                                         || $length > 3 && $character <= 0xFFFF
12168                                         // Outside of range of iunreserved codepoints
12169                                         || $character < 0x2D
12170                                         || $character > 0xEFFFD
12171                                         // Noncharacters
12172                                         || ($character & 0xFFFE) === 0xFFFE
12173                                         || $character >= 0xFDD0 && $character <= 0xFDEF
12174                                         // Everything else not in iunreserved (this is all BMP)
12175                                         || $character === 0x2F
12176                                         || $character > 0x39 && $character < 0x41
12177                                         || $character > 0x5A && $character < 0x61
12178                                         || $character > 0x7A && $character < 0x7E
12179                                         || $character > 0x7E && $character < 0xA0
12180                                         || $character > 0xD7FF && $character < 0xF900
12181                                 )
12182                                 {
12183                                         for ($j = $start; $j <= $i; $j++)
12184                                         {
12185                                                 $string .= '%' . strtoupper($bytes[$j]);
12186                                         }
12187                                 }
12188                                 else
12189                                 {
12190                                         for ($j = $start; $j <= $i; $j++)
12191                                         {
12192                                                 $string .= chr(hexdec($bytes[$j]));
12193                                         }
12194                                 }
12195                         }
12196                 }
12197
12198                 // If we have any bytes left over they are invalid (i.e., we are
12199                 // mid-way through a multi-byte sequence)
12200                 if ($remaining)
12201                 {
12202                         for ($j = $start; $j < $len; $j++)
12203                         {
12204                                 $string .= '%' . strtoupper($bytes[$j]);
12205                         }
12206                 }
12207
12208                 return $string;
12209         }
12210
12211         /**
12212          * Check if the object represents a valid IRI
12213          *
12214          * @access public
12215          * @return bool
12216          */
12217         function is_valid()
12218         {
12219                 return array_sum($this->valid) === count($this->valid);
12220         }
12221
12222         /**
12223          * Set the scheme. Returns true on success, false on failure (if there are
12224          * any invalid characters).
12225          *
12226          * @access public
12227          * @param string $scheme
12228          * @return bool
12229          */
12230         function set_scheme($scheme)
12231         {
12232                 if ($scheme === null || $scheme === '')
12233                 {
12234                         $this->scheme = null;
12235                 }
12236                 else
12237                 {
12238                         $len = strlen($scheme);
12239                         switch (true)
12240                         {
12241                                 case $len > 1:
12242                                         if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1))
12243                                         {
12244                                                 $this->scheme = null;
12245                                                 $this->valid[__FUNCTION__] = false;
12246                                                 return false;
12247                                         }
12248
12249                                 case $len > 0:
12250                                         if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1))
12251                                         {
12252                                                 $this->scheme = null;
12253                                                 $this->valid[__FUNCTION__] = false;
12254                                                 return false;
12255                                         }
12256                         }
12257                         $this->scheme = strtolower($scheme);
12258                 }
12259                 $this->valid[__FUNCTION__] = true;
12260                 return true;
12261         }
12262
12263         /**
12264          * Set the authority. Returns true on success, false on failure (if there are
12265          * any invalid characters).
12266          *
12267          * @access public
12268          * @param string $authority
12269          * @return bool
12270          */
12271         function set_authority($authority)
12272         {
12273                 if (($userinfo_end = strrpos($authority, '@')) !== false)
12274                 {
12275                         $userinfo = substr($authority, 0, $userinfo_end);
12276                         $authority = substr($authority, $userinfo_end + 1);
12277                 }
12278                 else
12279                 {
12280                         $userinfo = null;
12281                 }
12282
12283                 if (($port_start = strpos($authority, ':')) !== false)
12284                 {
12285                         $port = substr($authority, $port_start + 1);
12286                         $authority = substr($authority, 0, $port_start);
12287                 }
12288                 else
12289                 {
12290                         $port = null;
12291                 }
12292
12293                 return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port);
12294         }
12295
12296         /**
12297          * Set the userinfo.
12298          *
12299          * @access public
12300          * @param string $userinfo
12301          * @return bool
12302          */
12303         function set_userinfo($userinfo)
12304         {
12305                 if ($userinfo === null || $userinfo === '')
12306                 {
12307                         $this->userinfo = null;
12308                 }
12309                 else
12310                 {
12311                         $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:');
12312                 }
12313                 $this->valid[__FUNCTION__] = true;
12314                 return true;
12315         }
12316
12317         /**
12318          * Set the host. Returns true on success, false on failure (if there are
12319          * any invalid characters).
12320          *
12321          * @access public
12322          * @param string $host
12323          * @return bool
12324          */
12325         function set_host($host)
12326         {
12327                 if ($host === null || $host === '')
12328                 {
12329                         $this->host = null;
12330                         $this->valid[__FUNCTION__] = true;
12331                         return true;
12332                 }
12333                 elseif ($host[0] === '[' && substr($host, -1) === ']')
12334                 {
12335                         if (Net_IPv6::checkIPv6(substr($host, 1, -1)))
12336                         {
12337                                 $this->host = $host;
12338                                 $this->valid[__FUNCTION__] = true;
12339                                 return true;
12340                         }
12341                         else
12342                         {
12343                                 $this->host = null;
12344                                 $this->valid[__FUNCTION__] = false;
12345                                 return false;
12346                         }
12347                 }
12348                 else
12349                 {
12350                         $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE);
12351                         $this->valid[__FUNCTION__] = true;
12352                         return true;
12353                 }
12354         }
12355
12356         /**
12357          * Set the port. Returns true on success, false on failure (if there are
12358          * any invalid characters).
12359          *
12360          * @access public
12361          * @param string $port
12362          * @return bool
12363          */
12364         function set_port($port)
12365         {
12366                 if ($port === null || $port === '')
12367                 {
12368                         $this->port = null;
12369                         $this->valid[__FUNCTION__] = true;
12370                         return true;
12371                 }
12372                 elseif (strspn($port, '0123456789') === strlen($port))
12373                 {
12374                         $this->port = (int) $port;
12375                         $this->valid[__FUNCTION__] = true;
12376                         return true;
12377                 }
12378                 else
12379                 {
12380                         $this->port = null;
12381                         $this->valid[__FUNCTION__] = false;
12382                         return false;
12383                 }
12384         }
12385
12386         /**
12387          * Set the path.
12388          *
12389          * @access public
12390          * @param string $path
12391          * @return bool
12392          */
12393         function set_path($path)
12394         {
12395                 if ($path === null || $path === '')
12396                 {
12397                         $this->path = null;
12398                         $this->valid[__FUNCTION__] = true;
12399                         return true;
12400                 }
12401                 elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null)
12402                 {
12403                         $this->path = null;
12404                         $this->valid[__FUNCTION__] = false;
12405                         return false;
12406                 }
12407                 else
12408                 {
12409                         $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/');
12410                         if ($this->scheme !== null)
12411                         {
12412                                 $this->path = $this->remove_dot_segments($this->path);
12413                         }
12414                         $this->valid[__FUNCTION__] = true;
12415                         return true;
12416                 }
12417         }
12418
12419         /**
12420          * Set the query.
12421          *
12422          * @access public
12423          * @param string $query
12424          * @return bool
12425          */
12426         function set_query($query)
12427         {
12428                 if ($query === null || $query === '')
12429                 {
12430                         $this->query = null;
12431                 }
12432                 else
12433                 {
12434                         $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?&=');
12435                 }
12436                 $this->valid[__FUNCTION__] = true;
12437                 return true;
12438         }
12439
12440         /**
12441          * Set the fragment.
12442          *
12443          * @access public
12444          * @param string $fragment
12445          * @return bool
12446          */
12447         function set_fragment($fragment)
12448         {
12449                 if ($fragment === null || $fragment === '')
12450                 {
12451                         $this->fragment = null;
12452                 }
12453                 else
12454                 {
12455                         $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?');
12456                 }
12457                 $this->valid[__FUNCTION__] = true;
12458                 return true;
12459         }
12460
12461         /**
12462          * Get the complete IRI
12463          *
12464          * @access public
12465          * @return string
12466          */
12467         function get_iri()
12468         {
12469                 $iri = '';
12470                 if ($this->scheme !== null)
12471                 {
12472                         $iri .= $this->scheme . ':';
12473                 }
12474                 if (($authority = $this->get_authority()) !== null)
12475                 {
12476                         $iri .= '//' . $authority;
12477                 }
12478                 if ($this->path !== null)
12479                 {
12480                         $iri .= $this->path;
12481                 }
12482                 if ($this->query !== null)
12483                 {
12484                         $iri .= '?' . $this->query;
12485                 }
12486                 if ($this->fragment !== null)
12487                 {
12488                         $iri .= '#' . $this->fragment;
12489                 }
12490
12491                 if ($iri !== '')
12492                 {
12493                         return $iri;
12494                 }
12495                 else
12496                 {
12497                         return null;
12498                 }
12499         }
12500
12501         /**
12502          * Get the scheme
12503          *
12504          * @access public
12505          * @return string
12506          */
12507         function get_scheme()
12508         {
12509                 return $this->scheme;
12510         }
12511
12512         /**
12513          * Get the complete authority
12514          *
12515          * @access public
12516          * @return string
12517          */
12518         function get_authority()
12519         {
12520                 $authority = '';
12521                 if ($this->userinfo !== null)
12522                 {
12523                         $authority .= $this->userinfo . '@';
12524                 }
12525                 if ($this->host !== null)
12526                 {
12527                         $authority .= $this->host;
12528                 }
12529                 if ($this->port !== null)
12530                 {
12531                         $authority .= ':' . $this->port;
12532                 }
12533
12534                 if ($authority !== '')
12535                 {
12536                         return $authority;
12537                 }
12538                 else
12539                 {
12540                         return null;
12541                 }
12542         }
12543
12544         /**
12545          * Get the user information
12546          *
12547          * @access public
12548          * @return string
12549          */
12550         function get_userinfo()
12551         {
12552                 return $this->userinfo;
12553         }
12554
12555         /**
12556          * Get the host
12557          *
12558          * @access public
12559          * @return string
12560          */
12561         function get_host()
12562         {
12563                 return $this->host;
12564         }
12565
12566         /**
12567          * Get the port
12568          *
12569          * @access public
12570          * @return string
12571          */
12572         function get_port()
12573         {
12574                 return $this->port;
12575         }
12576
12577         /**
12578          * Get the path
12579          *
12580          * @access public
12581          * @return string
12582          */
12583         function get_path()
12584         {
12585                 return $this->path;
12586         }
12587
12588         /**
12589          * Get the query
12590          *
12591          * @access public
12592          * @return string
12593          */
12594         function get_query()
12595         {
12596                 return $this->query;
12597         }
12598
12599         /**
12600          * Get the fragment
12601          *
12602          * @access public
12603          * @return string
12604          */
12605         function get_fragment()
12606         {
12607                 return $this->fragment;
12608         }
12609 }
12610
12611 /**
12612  * Class to validate and to work with IPv6 addresses.
12613  *
12614  * @package SimplePie
12615  * @copyright 2003-2005 The PHP Group
12616  * @license http://www.opensource.org/licenses/bsd-license.php
12617  * @link http://pear.php.net/package/Net_IPv6
12618  * @author Alexander Merz <alexander.merz@web.de>
12619  * @author elfrink at introweb dot nl
12620  * @author Josh Peck <jmp at joshpeck dot org>
12621  * @author Geoffrey Sneddon <geoffers@gmail.com>
12622  */
12623 class SimplePie_Net_IPv6
12624 {
12625         /**
12626          * Removes a possible existing netmask specification of an IP address.
12627          *
12628          * @param string $ip the (compressed) IP as Hex representation
12629          * @return string the IP the without netmask
12630          * @since 1.1.0
12631          * @access public
12632          * @static
12633          */
12634         function removeNetmaskSpec($ip)
12635         {
12636                 if (strpos($ip, '/') !== false)
12637                 {
12638                         list($addr, $nm) = explode('/', $ip);
12639                 }
12640                 else
12641                 {
12642                         $addr = $ip;
12643                 }
12644                 return $addr;
12645         }
12646
12647         /**
12648          * Uncompresses an IPv6 address
12649          *
12650          * RFC 2373 allows you to compress zeros in an address to '::'. This
12651          * function expects an valid IPv6 address and expands the '::' to
12652          * the required zeros.
12653          *
12654          * Example:      FF01::101      ->      FF01:0:0:0:0:0:0:101
12655          *                       ::1            ->      0:0:0:0:0:0:0:1
12656          *
12657          * @access public
12658          * @static
12659          * @param string $ip a valid IPv6-address (hex format)
12660          * @return string the uncompressed IPv6-address (hex format)
12661          */
12662         function Uncompress($ip)
12663         {
12664                 $uip = SimplePie_Net_IPv6::removeNetmaskSpec($ip);
12665                 $c1 = -1;
12666                 $c2 = -1;
12667                 if (strpos($ip, '::') !== false)
12668                 {
12669                         list($ip1, $ip2) = explode('::', $ip);
12670                         if ($ip1 === '')
12671                         {
12672                                 $c1 = -1;
12673                         }
12674                         else
12675                         {
12676                                 $pos = 0;
12677                                 if (($pos = substr_count($ip1, ':')) > 0)
12678                                 {
12679                                         $c1 = $pos;
12680                                 }
12681                                 else
12682                                 {
12683                                         $c1 = 0;
12684                                 }
12685                         }
12686                         if ($ip2 === '')
12687                         {
12688                                 $c2 = -1;
12689                         }
12690                         else
12691                         {
12692                                 $pos = 0;
12693                                 if (($pos = substr_count($ip2, ':')) > 0)
12694                                 {
12695                                         $c2 = $pos;
12696                                 }
12697                                 else
12698                                 {
12699                                         $c2 = 0;
12700                                 }
12701                         }
12702                         if (strstr($ip2, '.'))
12703                         {
12704                                 $c2++;
12705                         }
12706                         // ::
12707                         if ($c1 === -1 && $c2 === -1)
12708                         {
12709                                 $uip = '0:0:0:0:0:0:0:0';
12710                         }
12711                         // ::xxx
12712                         else if ($c1 === -1)
12713                         {
12714                                 $fill = str_repeat('0:', 7 - $c2);
12715                                 $uip =  str_replace('::', $fill, $uip);
12716                         }
12717                         // xxx::
12718                         else if ($c2 === -1)
12719                         {
12720                                 $fill = str_repeat(':0', 7 - $c1);
12721                                 $uip =  str_replace('::', $fill, $uip);
12722                         }
12723                         // xxx::xxx
12724                         else
12725                         {
12726                                 $fill = str_repeat(':0:', 6 - $c2 - $c1);
12727                                 $uip =  str_replace('::', $fill, $uip);
12728                                 $uip =  str_replace('::', ':', $uip);
12729                         }
12730                 }
12731                 return $uip;
12732         }
12733
12734         /**
12735          * Splits an IPv6 address into the IPv6 and a possible IPv4 part
12736          *
12737          * RFC 2373 allows you to note the last two parts of an IPv6 address as
12738          * an IPv4 compatible address
12739          *
12740          * Example:      0:0:0:0:0:0:13.1.68.3
12741          *                       0:0:0:0:0:FFFF:129.144.52.38
12742          *
12743          * @access public
12744          * @static
12745          * @param string $ip a valid IPv6-address (hex format)
12746          * @return array [0] contains the IPv6 part, [1] the IPv4 part (hex format)
12747          */
12748         function SplitV64($ip)
12749         {
12750                 $ip = SimplePie_Net_IPv6::Uncompress($ip);
12751                 if (strstr($ip, '.'))
12752                 {
12753                         $pos = strrpos($ip, ':');
12754                         $ip[$pos] = '_';
12755                         $ipPart = explode('_', $ip);
12756                         return $ipPart;
12757                 }
12758                 else
12759                 {
12760                         return array($ip, '');
12761                 }
12762         }
12763
12764         /**
12765          * Checks an IPv6 address
12766          *
12767          * Checks if the given IP is IPv6-compatible
12768          *
12769          * @access public
12770          * @static
12771          * @param string $ip a valid IPv6-address
12772          * @return bool true if $ip is an IPv6 address
12773          */
12774         function checkIPv6($ip)
12775         {
12776                 $ipPart = SimplePie_Net_IPv6::SplitV64($ip);
12777                 $count = 0;
12778                 if (!empty($ipPart[0]))
12779                 {
12780                         $ipv6 = explode(':', $ipPart[0]);
12781                         for ($i = 0; $i < count($ipv6); $i++)
12782                         {
12783                                 $dec = hexdec($ipv6[$i]);
12784                                 $hex = strtoupper(preg_replace('/^[0]{1,3}(.*[0-9a-fA-F])$/', '\\1', $ipv6[$i]));
12785                                 if ($ipv6[$i] >= 0 && $dec <= 65535 && $hex === strtoupper(dechex($dec)))
12786                                 {
12787                                         $count++;
12788                                 }
12789                         }
12790                         if ($count === 8)
12791                         {
12792                                 return true;
12793                         }
12794                         elseif ($count === 6 && !empty($ipPart[1]))
12795                         {
12796                                 $ipv4 = explode('.', $ipPart[1]);
12797                                 $count = 0;
12798                                 foreach ($ipv4 as $ipv4_part)
12799                                 {
12800                                         if ($ipv4_part >= 0 && $ipv4_part <= 255 && preg_match('/^\d{1,3}$/', $ipv4_part))
12801                                         {
12802                                                 $count++;
12803                                         }
12804                                 }
12805                                 if ($count === 4)
12806                                 {
12807                                         return true;
12808                                 }
12809                         }
12810                         else
12811                         {
12812                                 return false;
12813                         }
12814
12815                 }
12816                 else
12817                 {
12818                         return false;
12819                 }
12820         }
12821 }
12822
12823 /**
12824  * Date Parser
12825  *
12826  * @package SimplePie
12827  */
12828 class SimplePie_Parse_Date
12829 {
12830         /**
12831          * Input data
12832          *
12833          * @access protected
12834          * @var string
12835          */
12836         var $date;
12837
12838         /**
12839          * List of days, calendar day name => ordinal day number in the week
12840          *
12841          * @access protected
12842          * @var array
12843          */
12844         var $day = array(
12845                 // English
12846                 'mon' => 1,
12847                 'monday' => 1,
12848                 'tue' => 2,
12849                 'tuesday' => 2,
12850                 'wed' => 3,
12851                 'wednesday' => 3,
12852                 'thu' => 4,
12853                 'thursday' => 4,
12854                 'fri' => 5,
12855                 'friday' => 5,
12856                 'sat' => 6,
12857                 'saturday' => 6,
12858                 'sun' => 7,
12859                 'sunday' => 7,
12860                 // Dutch
12861                 'maandag' => 1,
12862                 'dinsdag' => 2,
12863                 'woensdag' => 3,
12864                 'donderdag' => 4,
12865                 'vrijdag' => 5,
12866                 'zaterdag' => 6,
12867                 'zondag' => 7,
12868                 // French
12869                 'lundi' => 1,
12870                 'mardi' => 2,
12871                 'mercredi' => 3,
12872                 'jeudi' => 4,
12873                 'vendredi' => 5,
12874                 'samedi' => 6,
12875                 'dimanche' => 7,
12876                 // German
12877                 'montag' => 1,
12878                 'dienstag' => 2,
12879                 'mittwoch' => 3,
12880                 'donnerstag' => 4,
12881                 'freitag' => 5,
12882                 'samstag' => 6,
12883                 'sonnabend' => 6,
12884                 'sonntag' => 7,
12885                 // Italian
12886                 'lunedì' => 1,
12887                 'martedì' => 2,
12888                 'mercoledì' => 3,
12889                 'giovedì' => 4,
12890                 'venerdì' => 5,
12891                 'sabato' => 6,
12892                 'domenica' => 7,
12893                 // Spanish
12894                 'lunes' => 1,
12895                 'martes' => 2,
12896                 'miércoles' => 3,
12897                 'jueves' => 4,
12898                 'viernes' => 5,
12899                 'sábado' => 6,
12900                 'domingo' => 7,
12901                 // Finnish
12902                 'maanantai' => 1,
12903                 'tiistai' => 2,
12904                 'keskiviikko' => 3,
12905                 'torstai' => 4,
12906                 'perjantai' => 5,
12907                 'lauantai' => 6,
12908                 'sunnuntai' => 7,
12909                 // Hungarian
12910                 'hétfő' => 1,
12911                 'kedd' => 2,
12912                 'szerda' => 3,
12913                 'csütörtok' => 4,
12914                 'péntek' => 5,
12915                 'szombat' => 6,
12916                 'vasárnap' => 7,
12917                 // Greek
12918                 'Δευ' => 1,
12919                 'Τρι' => 2,
12920                 'Τετ' => 3,
12921                 'Πεμ' => 4,
12922                 'Παρ' => 5,
12923                 'Σαβ' => 6,
12924                 'Κυρ' => 7,
12925         );
12926
12927         /**
12928          * List of months, calendar month name => calendar month number
12929          *
12930          * @access protected
12931          * @var array
12932          */
12933         var $month = array(
12934                 // English
12935                 'jan' => 1,
12936                 'january' => 1,
12937                 'feb' => 2,
12938                 'february' => 2,
12939                 'mar' => 3,
12940                 'march' => 3,
12941                 'apr' => 4,
12942                 'april' => 4,
12943                 'may' => 5,
12944                 // No long form of May
12945                 'jun' => 6,
12946                 'june' => 6,
12947                 'jul' => 7,
12948                 'july' => 7,
12949                 'aug' => 8,
12950                 'august' => 8,
12951                 'sep' => 9,
12952                 'september' => 8,
12953                 'oct' => 10,
12954                 'october' => 10,
12955                 'nov' => 11,
12956                 'november' => 11,
12957                 'dec' => 12,
12958                 'december' => 12,
12959                 // Dutch
12960                 'januari' => 1,
12961                 'februari' => 2,
12962                 'maart' => 3,
12963                 'april' => 4,
12964                 'mei' => 5,
12965                 'juni' => 6,
12966                 'juli' => 7,
12967                 'augustus' => 8,
12968                 'september' => 9,
12969                 'oktober' => 10,
12970                 'november' => 11,
12971                 'december' => 12,
12972                 // French
12973                 'janvier' => 1,
12974                 'février' => 2,
12975                 'mars' => 3,
12976                 'avril' => 4,
12977                 'mai' => 5,
12978                 'juin' => 6,
12979                 'juillet' => 7,
12980                 'août' => 8,
12981                 'septembre' => 9,
12982                 'octobre' => 10,
12983                 'novembre' => 11,
12984                 'décembre' => 12,
12985                 // German
12986                 'januar' => 1,
12987                 'februar' => 2,
12988                 'märz' => 3,
12989                 'april' => 4,
12990                 'mai' => 5,
12991                 'juni' => 6,
12992                 'juli' => 7,
12993                 'august' => 8,
12994                 'september' => 9,
12995                 'oktober' => 10,
12996                 'november' => 11,
12997                 'dezember' => 12,
12998                 // Italian
12999                 'gennaio' => 1,
13000                 'febbraio' => 2,
13001                 'marzo' => 3,
13002                 'aprile' => 4,
13003                 'maggio' => 5,
13004                 'giugno' => 6,
13005                 'luglio' => 7,
13006                 'agosto' => 8,
13007                 'settembre' => 9,
13008                 'ottobre' => 10,
13009                 'novembre' => 11,
13010                 'dicembre' => 12,
13011                 // Spanish
13012                 'enero' => 1,
13013                 'febrero' => 2,
13014                 'marzo' => 3,
13015                 'abril' => 4,
13016                 'mayo' => 5,
13017                 'junio' => 6,
13018                 'julio' => 7,
13019                 'agosto' => 8,
13020                 'septiembre' => 9,
13021                 'setiembre' => 9,
13022                 'octubre' => 10,
13023                 'noviembre' => 11,
13024                 'diciembre' => 12,
13025                 // Finnish
13026                 'tammikuu' => 1,
13027                 'helmikuu' => 2,
13028                 'maaliskuu' => 3,
13029                 'huhtikuu' => 4,
13030                 'toukokuu' => 5,
13031                 'kesäkuu' => 6,
13032                 'heinäkuu' => 7,
13033                 'elokuu' => 8,
13034                 'suuskuu' => 9,
13035                 'lokakuu' => 10,
13036                 'marras' => 11,
13037                 'joulukuu' => 12,
13038                 // Hungarian
13039                 'január' => 1,
13040                 'február' => 2,
13041                 'március' => 3,
13042                 'április' => 4,
13043                 'május' => 5,
13044                 'június' => 6,
13045                 'július' => 7,
13046                 'augusztus' => 8,
13047                 'szeptember' => 9,
13048                 'október' => 10,
13049                 'november' => 11,
13050                 'december' => 12,
13051                 // Greek
13052                 'Ιαν' => 1,
13053                 'Φεβ' => 2,
13054                 'Μάώ' => 3,
13055                 'Μαώ' => 3,
13056                 'Απρ' => 4,
13057                 'Μάι' => 5,
13058                 'Μαϊ' => 5,
13059                 'Μαι' => 5,
13060                 'Ιούν' => 6,
13061                 'Ιον' => 6,
13062                 'Ιούλ' => 7,
13063                 'Ιολ' => 7,
13064                 'Αύγ' => 8,
13065                 'Αυγ' => 8,
13066                 'Σεπ' => 9,
13067                 'Οκτ' => 10,
13068                 'Νοέ' => 11,
13069                 'Δεκ' => 12,
13070         );
13071
13072         /**
13073          * List of timezones, abbreviation => offset from UTC
13074          *
13075          * @access protected
13076          * @var array
13077          */
13078         var $timezone = array(
13079                 'ACDT' => 37800,
13080                 'ACIT' => 28800,
13081                 'ACST' => 34200,
13082                 'ACT' => -18000,
13083                 'ACWDT' => 35100,
13084                 'ACWST' => 31500,
13085                 'AEDT' => 39600,
13086                 'AEST' => 36000,
13087                 'AFT' => 16200,
13088                 'AKDT' => -28800,
13089                 'AKST' => -32400,
13090                 'AMDT' => 18000,
13091                 'AMT' => -14400,
13092                 'ANAST' => 46800,
13093                 'ANAT' => 43200,
13094                 'ART' => -10800,
13095                 'AZOST' => -3600,
13096                 'AZST' => 18000,
13097                 'AZT' => 14400,
13098                 'BIOT' => 21600,
13099                 'BIT' => -43200,
13100                 'BOT' => -14400,
13101                 'BRST' => -7200,
13102                 'BRT' => -10800,
13103                 'BST' => 3600,
13104                 'BTT' => 21600,
13105                 'CAST' => 18000,
13106                 'CAT' => 7200,
13107                 'CCT' => 23400,
13108                 'CDT' => -18000,
13109                 'CEDT' => 7200,
13110                 'CET' => 3600,
13111                 'CGST' => -7200,
13112                 'CGT' => -10800,
13113                 'CHADT' => 49500,
13114                 'CHAST' => 45900,
13115                 'CIST' => -28800,
13116                 'CKT' => -36000,
13117                 'CLDT' => -10800,
13118                 'CLST' => -14400,
13119                 'COT' => -18000,
13120                 'CST' => -21600,
13121                 'CVT' => -3600,
13122                 'CXT' => 25200,
13123                 'DAVT' => 25200,
13124                 'DTAT' => 36000,
13125                 'EADT' => -18000,
13126                 'EAST' => -21600,
13127                 'EAT' => 10800,
13128                 'ECT' => -18000,
13129                 'EDT' => -14400,
13130                 'EEST' => 10800,
13131                 'EET' => 7200,
13132                 'EGT' => -3600,
13133                 'EKST' => 21600,
13134                 'EST' => -18000,
13135                 'FJT' => 43200,
13136                 'FKDT' => -10800,
13137                 'FKST' => -14400,
13138                 'FNT' => -7200,
13139                 'GALT' => -21600,
13140                 'GEDT' => 14400,
13141                 'GEST' => 10800,
13142                 'GFT' => -10800,
13143                 'GILT' => 43200,
13144                 'GIT' => -32400,
13145                 'GST' => 14400,
13146                 'GST' => -7200,
13147                 'GYT' => -14400,
13148                 'HAA' => -10800,
13149                 'HAC' => -18000,
13150                 'HADT' => -32400,
13151                 'HAE' => -14400,
13152                 'HAP' => -25200,
13153                 'HAR' => -21600,
13154                 'HAST' => -36000,
13155                 'HAT' => -9000,
13156                 'HAY' => -28800,
13157                 'HKST' => 28800,
13158                 'HMT' => 18000,
13159                 'HNA' => -14400,
13160                 'HNC' => -21600,
13161                 'HNE' => -18000,
13162                 'HNP' => -28800,
13163                 'HNR' => -25200,
13164                 'HNT' => -12600,
13165                 'HNY' => -32400,
13166                 'IRDT' => 16200,
13167                 'IRKST' => 32400,
13168                 'IRKT' => 28800,
13169                 'IRST' => 12600,
13170                 'JFDT' => -10800,
13171                 'JFST' => -14400,
13172                 'JST' => 32400,
13173                 'KGST' => 21600,
13174                 'KGT' => 18000,
13175                 'KOST' => 39600,
13176                 'KOVST' => 28800,
13177                 'KOVT' => 25200,
13178                 'KRAST' => 28800,
13179                 'KRAT' => 25200,
13180                 'KST' => 32400,
13181                 'LHDT' => 39600,
13182                 'LHST' => 37800,
13183                 'LINT' => 50400,
13184                 'LKT' => 21600,
13185                 'MAGST' => 43200,
13186                 'MAGT' => 39600,
13187                 'MAWT' => 21600,
13188                 'MDT' => -21600,
13189                 'MESZ' => 7200,
13190                 'MEZ' => 3600,
13191                 'MHT' => 43200,
13192                 'MIT' => -34200,
13193                 'MNST' => 32400,
13194                 'MSDT' => 14400,
13195                 'MSST' => 10800,
13196                 'MST' => -25200,
13197                 'MUT' => 14400,
13198                 'MVT' => 18000,
13199                 'MYT' => 28800,
13200                 'NCT' => 39600,
13201                 'NDT' => -9000,
13202                 'NFT' => 41400,
13203                 'NMIT' => 36000,
13204                 'NOVST' => 25200,
13205                 'NOVT' => 21600,
13206                 'NPT' => 20700,
13207                 'NRT' => 43200,
13208                 'NST' => -12600,
13209                 'NUT' => -39600,
13210                 'NZDT' => 46800,
13211                 'NZST' => 43200,
13212                 'OMSST' => 25200,
13213                 'OMST' => 21600,
13214                 'PDT' => -25200,
13215                 'PET' => -18000,
13216                 'PETST' => 46800,
13217                 'PETT' => 43200,
13218                 'PGT' => 36000,
13219                 'PHOT' => 46800,
13220                 'PHT' => 28800,
13221                 'PKT' => 18000,
13222                 'PMDT' => -7200,
13223                 'PMST' => -10800,
13224                 'PONT' => 39600,
13225                 'PST' => -28800,
13226                 'PWT' => 32400,
13227                 'PYST' => -10800,
13228                 'PYT' => -14400,
13229                 'RET' => 14400,
13230                 'ROTT' => -10800,
13231                 'SAMST' => 18000,
13232                 'SAMT' => 14400,
13233                 'SAST' => 7200,
13234                 'SBT' => 39600,
13235                 'SCDT' => 46800,
13236                 'SCST' => 43200,
13237                 'SCT' => 14400,
13238                 'SEST' => 3600,
13239                 'SGT' => 28800,
13240                 'SIT' => 28800,
13241                 'SRT' => -10800,
13242                 'SST' => -39600,
13243                 'SYST' => 10800,
13244                 'SYT' => 7200,
13245                 'TFT' => 18000,
13246                 'THAT' => -36000,
13247                 'TJT' => 18000,
13248                 'TKT' => -36000,
13249                 'TMT' => 18000,
13250                 'TOT' => 46800,
13251                 'TPT' => 32400,
13252                 'TRUT' => 36000,
13253                 'TVT' => 43200,
13254                 'TWT' => 28800,
13255                 'UYST' => -7200,
13256                 'UYT' => -10800,
13257                 'UZT' => 18000,
13258                 'VET' => -14400,
13259                 'VLAST' => 39600,
13260                 'VLAT' => 36000,
13261                 'VOST' => 21600,
13262                 'VUT' => 39600,
13263                 'WAST' => 7200,
13264                 'WAT' => 3600,
13265                 'WDT' => 32400,
13266                 'WEST' => 3600,
13267                 'WFT' => 43200,
13268                 'WIB' => 25200,
13269                 'WIT' => 32400,
13270                 'WITA' => 28800,
13271                 'WKST' => 18000,
13272                 'WST' => 28800,
13273                 'YAKST' => 36000,
13274                 'YAKT' => 32400,
13275                 'YAPT' => 36000,
13276                 'YEKST' => 21600,
13277                 'YEKT' => 18000,
13278         );
13279
13280         /**
13281          * Cached PCRE for SimplePie_Parse_Date::$day
13282          *
13283          * @access protected
13284          * @var string
13285          */
13286         var $day_pcre;
13287
13288         /**
13289          * Cached PCRE for SimplePie_Parse_Date::$month
13290          *
13291          * @access protected
13292          * @var string
13293          */
13294         var $month_pcre;
13295
13296         /**
13297          * Array of user-added callback methods
13298          *
13299          * @access private
13300          * @var array
13301          */
13302         var $built_in = array();
13303
13304         /**
13305          * Array of user-added callback methods
13306          *
13307          * @access private
13308          * @var array
13309          */
13310         var $user = array();
13311
13312         /**
13313          * Create new SimplePie_Parse_Date object, and set self::day_pcre,
13314          * self::month_pcre, and self::built_in
13315          *
13316          * @access private
13317          */
13318         function SimplePie_Parse_Date()
13319         {
13320                 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
13321                 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
13322
13323                 static $cache;
13324                 if (!isset($cache[get_class($this)]))
13325                 {
13326                         $all_methods = get_class_methods($this);
13327
13328                         foreach ($all_methods as $method)
13329                         {
13330                                 if (strtolower(substr($method, 0, 5)) === 'date_')
13331                                 {
13332                                         $cache[get_class($this)][] = $method;
13333                                 }
13334                         }
13335                 }
13336
13337                 foreach ($cache[get_class($this)] as $method)
13338                 {
13339                         $this->built_in[] = $method;
13340                 }
13341         }
13342
13343         /**
13344          * Get the object
13345          *
13346          * @access public
13347          */
13348         function get()
13349         {
13350                 static $object;
13351                 if (!$object)
13352                 {
13353                         $object =& new SimplePie_Parse_Date;
13354                 }
13355                 return $object;
13356         }
13357
13358         /**
13359          * Parse a date
13360          *
13361          * @final
13362          * @access public
13363          * @param string $date Date to parse
13364          * @return int Timestamp corresponding to date string, or false on failure
13365          */
13366         function parse($date)
13367         {
13368                 foreach ($this->user as $method)
13369                 {
13370                         if (($returned = call_user_func($method, $date)) !== false)
13371                         {
13372                                 return $returned;
13373                         }
13374                 }
13375
13376                 foreach ($this->built_in as $method)
13377                 {
13378                         if (($returned = call_user_func(array(&$this, $method), $date)) !== false)
13379                         {
13380                                 return $returned;
13381                         }
13382                 }
13383
13384                 return false;
13385         }
13386
13387         /**
13388          * Add a callback method to parse a date
13389          *
13390          * @final
13391          * @access public
13392          * @param callback $callback
13393          */
13394         function add_callback($callback)
13395         {
13396                 if (is_callable($callback))
13397                 {
13398                         $this->user[] = $callback;
13399                 }
13400                 else
13401                 {
13402                         trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
13403                 }
13404         }
13405
13406         /**
13407          * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
13408          * well as allowing any of upper or lower case "T", horizontal tabs, or
13409          * spaces to be used as the time seperator (including more than one))
13410          *
13411          * @access protected
13412          * @return int Timestamp
13413          */
13414         function date_w3cdtf($date)
13415         {
13416                 static $pcre;
13417                 if (!$pcre)
13418                 {
13419                         $year = '([0-9]{4})';
13420                         $month = $day = $hour = $minute = $second = '([0-9]{2})';
13421                         $decimal = '([0-9]*)';
13422                         $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
13423                         $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
13424                 }
13425                 if (preg_match($pcre, $date, $match))
13426                 {
13427                         /*
13428                         Capturing subpatterns:
13429                         1: Year
13430                         2: Month
13431                         3: Day
13432                         4: Hour
13433                         5: Minute
13434                         6: Second
13435                         7: Decimal fraction of a second
13436                         8: Zulu
13437                         9: Timezone ±
13438                         10: Timezone hours
13439                         11: Timezone minutes
13440                         */
13441
13442                         // Fill in empty matches
13443                         for ($i = count($match); $i <= 3; $i++)
13444                         {
13445                                 $match[$i] = '1';
13446                         }
13447
13448                         for ($i = count($match); $i <= 7; $i++)
13449                         {
13450                                 $match[$i] = '0';
13451                         }
13452
13453                         // Numeric timezone
13454                         if (isset($match[9]) && $match[9] !== '')
13455                         {
13456                                 $timezone = $match[10] * 3600;
13457                                 $timezone += $match[11] * 60;
13458                                 if ($match[9] === '-')
13459                                 {
13460                                         $timezone = 0 - $timezone;
13461                                 }
13462                         }
13463                         else
13464                         {
13465                                 $timezone = 0;
13466                         }
13467
13468                         // Convert the number of seconds to an integer, taking decimals into account
13469                         $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
13470
13471                         return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
13472                 }
13473                 else
13474                 {
13475                         return false;
13476                 }
13477         }
13478
13479         /**
13480          * Remove RFC822 comments
13481          *
13482          * @access protected
13483          * @param string $data Data to strip comments from
13484          * @return string Comment stripped string
13485          */
13486         function remove_rfc2822_comments($string)
13487         {
13488                 $string = (string) $string;
13489                 $position = 0;
13490                 $length = strlen($string);
13491                 $depth = 0;
13492
13493                 $output = '';
13494
13495                 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
13496                 {
13497                         $output .= substr($string, $position, $pos - $position);
13498                         $position = $pos + 1;
13499                         if ($string[$pos - 1] !== '\\')
13500                         {
13501                                 $depth++;
13502                                 while ($depth && $position < $length)
13503                                 {
13504                                         $position += strcspn($string, '()', $position);
13505                                         if ($string[$position - 1] === '\\')
13506                                         {
13507                                                 $position++;
13508                                                 continue;
13509                                         }
13510                                         elseif (isset($string[$position]))
13511                                         {
13512                                                 switch ($string[$position])
13513                                                 {
13514                                                         case '(':
13515                                                                 $depth++;
13516                                                                 break;
13517
13518                                                         case ')':
13519                                                                 $depth--;
13520                                                                 break;
13521                                                 }
13522                                                 $position++;
13523                                         }
13524                                         else
13525                                         {
13526                                                 break;
13527                                         }
13528                                 }
13529                         }
13530                         else
13531                         {
13532                                 $output .= '(';
13533                         }
13534                 }
13535                 $output .= substr($string, $position);
13536
13537                 return $output;
13538         }
13539
13540         /**
13541          * Parse RFC2822's date format
13542          *
13543          * @access protected
13544          * @return int Timestamp
13545          */
13546         function date_rfc2822($date)
13547         {
13548                 static $pcre;
13549                 if (!$pcre)
13550                 {
13551                         $wsp = '[\x09\x20]';
13552                         $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
13553                         $optional_fws = $fws . '?';
13554                         $day_name = $this->day_pcre;
13555                         $month = $this->month_pcre;
13556                         $day = '([0-9]{1,2})';
13557                         $hour = $minute = $second = '([0-9]{2})';
13558                         $year = '([0-9]{2,4})';
13559                         $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
13560                         $character_zone = '([A-Z]{1,5})';
13561                         $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
13562                         $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';
13563                 }
13564                 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
13565                 {
13566                         /*
13567                         Capturing subpatterns:
13568                         1: Day name
13569                         2: Day
13570                         3: Month
13571                         4: Year
13572                         5: Hour
13573                         6: Minute
13574                         7: Second
13575                         8: Timezone ±
13576                         9: Timezone hours
13577                         10: Timezone minutes
13578                         11: Alphabetic timezone
13579                         */
13580
13581                         // Find the month number
13582                         $month = $this->month[strtolower($match[3])];
13583
13584                         // Numeric timezone
13585                         if ($match[8] !== '')
13586                         {
13587                                 $timezone = $match[9] * 3600;
13588                                 $timezone += $match[10] * 60;
13589                                 if ($match[8] === '-')
13590                                 {
13591                                         $timezone = 0 - $timezone;
13592                                 }
13593                         }
13594                         // Character timezone
13595                         elseif (isset($this->timezone[strtoupper($match[11])]))
13596                         {
13597                                 $timezone = $this->timezone[strtoupper($match[11])];
13598                         }
13599                         // Assume everything else to be -0000
13600                         else
13601                         {
13602                                 $timezone = 0;
13603                         }
13604
13605                         // Deal with 2/3 digit years
13606                         if ($match[4] < 50)
13607                         {
13608                                 $match[4] += 2000;
13609                         }
13610                         elseif ($match[4] < 1000)
13611                         {
13612                                 $match[4] += 1900;
13613                         }
13614
13615                         // Second is optional, if it is empty set it to zero
13616                         if ($match[7] !== '')
13617                         {
13618                                 $second = $match[7];
13619                         }
13620                         else
13621                         {
13622                                 $second = 0;
13623                         }
13624
13625                         return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
13626                 }
13627                 else
13628                 {
13629                         return false;
13630                 }
13631         }
13632
13633         /**
13634          * Parse RFC850's date format
13635          *
13636          * @access protected
13637          * @return int Timestamp
13638          */
13639         function date_rfc850($date)
13640         {
13641                 static $pcre;
13642                 if (!$pcre)
13643                 {
13644                         $space = '[\x09\x20]+';
13645                         $day_name = $this->day_pcre;
13646                         $month = $this->month_pcre;
13647                         $day = '([0-9]{1,2})';
13648                         $year = $hour = $minute = $second = '([0-9]{2})';
13649                         $zone = '([A-Z]{1,5})';
13650                         $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
13651                 }
13652                 if (preg_match($pcre, $date, $match))
13653                 {
13654                         /*
13655                         Capturing subpatterns:
13656                         1: Day name
13657                         2: Day
13658                         3: Month
13659                         4: Year
13660                         5: Hour
13661                         6: Minute
13662                         7: Second
13663                         8: Timezone
13664                         */
13665
13666                         // Month
13667                         $month = $this->month[strtolower($match[3])];
13668
13669                         // Character timezone
13670                         if (isset($this->timezone[strtoupper($match[8])]))
13671                         {
13672                                 $timezone = $this->timezone[strtoupper($match[8])];
13673                         }
13674                         // Assume everything else to be -0000
13675                         else
13676                         {
13677                                 $timezone = 0;
13678                         }
13679
13680                         // Deal with 2 digit year
13681                         if ($match[4] < 50)
13682                         {
13683                                 $match[4] += 2000;
13684                         }
13685                         else
13686                         {
13687                                 $match[4] += 1900;
13688                         }
13689
13690                         return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
13691                 }
13692                 else
13693                 {
13694                         return false;
13695                 }
13696         }
13697
13698         /**
13699          * Parse C99's asctime()'s date format
13700          *
13701          * @access protected
13702          * @return int Timestamp
13703          */
13704         function date_asctime($date)
13705         {
13706                 static $pcre;
13707                 if (!$pcre)
13708                 {
13709                         $space = '[\x09\x20]+';
13710                         $wday_name = $this->day_pcre;
13711                         $mon_name = $this->month_pcre;
13712                         $day = '([0-9]{1,2})';
13713                         $hour = $sec = $min = '([0-9]{2})';
13714                         $year = '([0-9]{4})';
13715                         $terminator = '\x0A?\x00?';
13716                         $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
13717                 }
13718                 if (preg_match($pcre, $date, $match))
13719                 {
13720                         /*
13721                         Capturing subpatterns:
13722                         1: Day name
13723                         2: Month
13724                         3: Day
13725                         4: Hour
13726                         5: Minute
13727                         6: Second
13728                         7: Year
13729                         */
13730
13731                         $month = $this->month[strtolower($match[2])];
13732                         return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
13733                 }
13734                 else
13735                 {
13736                         return false;
13737                 }
13738         }
13739
13740         /**
13741          * Parse dates using strtotime()
13742          *
13743          * @access protected
13744          * @return int Timestamp
13745          */
13746         function date_strtotime($date)
13747         {
13748                 $strtotime = strtotime($date);
13749                 if ($strtotime === -1 || $strtotime === false)
13750                 {
13751                         return false;
13752                 }
13753                 else
13754                 {
13755                         return $strtotime;
13756                 }
13757         }
13758 }
13759
13760 /**
13761  * Content-type sniffing
13762  *
13763  * @package SimplePie
13764  */
13765 class SimplePie_Content_Type_Sniffer
13766 {
13767         /**
13768          * File object
13769          *
13770          * @var SimplePie_File
13771          * @access private
13772          */
13773         var $file;
13774
13775         /**
13776          * Create an instance of the class with the input file
13777          *
13778          * @access public
13779          * @param SimplePie_Content_Type_Sniffer $file Input file
13780          */
13781         function SimplePie_Content_Type_Sniffer($file)
13782         {
13783                 $this->file = $file;
13784         }
13785
13786         /**
13787          * Get the Content-Type of the specified file
13788          *
13789          * @access public
13790          * @return string Actual Content-Type
13791          */
13792         function get_type()
13793         {
13794                 if (isset($this->file->headers['content-type']))
13795                 {
13796                         if (!isset($this->file->headers['content-encoding'])
13797                                 && ($this->file->headers['content-type'] === 'text/plain'
13798                                         || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
13799                                         || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'))
13800                         {
13801                                 return $this->text_or_binary();
13802                         }
13803
13804                         if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
13805                         {
13806                                 $official = substr($this->file->headers['content-type'], 0, $pos);
13807                         }
13808                         else
13809                         {
13810                                 $official = $this->file->headers['content-type'];
13811                         }
13812                         $official = strtolower($official);
13813
13814                         if ($official === 'unknown/unknown'
13815                                 || $official === 'application/unknown')
13816                         {
13817                                 return $this->unknown();
13818                         }
13819                         elseif (substr($official, -4) === '+xml'
13820                                 || $official === 'text/xml'
13821                                 || $official === 'application/xml')
13822                         {
13823                                 return $official;
13824                         }
13825                         elseif (substr($official, 0, 6) === 'image/')
13826                         {
13827                                 if ($return = $this->image())
13828                                 {
13829                                         return $return;
13830                                 }
13831                                 else
13832                                 {
13833                                         return $official;
13834                                 }
13835                         }
13836                         elseif ($official === 'text/html')
13837                         {
13838                                 return $this->feed_or_html();
13839                         }
13840                         else
13841                         {
13842                                 return $official;
13843                         }
13844                 }
13845                 else
13846                 {
13847                         return $this->unknown();
13848                 }
13849         }
13850
13851         /**
13852          * Sniff text or binary
13853          *
13854          * @access private
13855          * @return string Actual Content-Type
13856          */
13857         function text_or_binary()
13858         {
13859                 if (substr($this->file->body, 0, 2) === "\xFE\xFF"
13860                         || substr($this->file->body, 0, 2) === "\xFF\xFE"
13861                         || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
13862                         || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
13863                 {
13864                         return 'text/plain';
13865                 }
13866                 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
13867                 {
13868                         return 'application/octect-stream';
13869                 }
13870                 else
13871                 {
13872                         return 'text/plain';
13873                 }
13874         }
13875
13876         /**
13877          * Sniff unknown
13878          *
13879          * @access private
13880          * @return string Actual Content-Type
13881          */
13882         function unknown()
13883         {
13884                 $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
13885                 if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
13886                         || strtolower(substr($this->file->body, $ws, 5)) === '<html'
13887                         || strtolower(substr($this->file->body, $ws, 7)) === '<script')
13888                 {
13889                         return 'text/html';
13890                 }
13891                 elseif (substr($this->file->body, 0, 5) === '%PDF-')
13892                 {
13893                         return 'application/pdf';
13894                 }
13895                 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
13896                 {
13897                         return 'application/postscript';
13898                 }
13899                 elseif (substr($this->file->body, 0, 6) === 'GIF87a'
13900                         || substr($this->file->body, 0, 6) === 'GIF89a')
13901                 {
13902                         return 'image/gif';
13903                 }
13904                 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
13905                 {
13906                         return 'image/png';
13907                 }
13908                 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
13909                 {
13910                         return 'image/jpeg';
13911                 }
13912                 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
13913                 {
13914                         return 'image/bmp';
13915                 }
13916                 else
13917                 {
13918                         return $this->text_or_binary();
13919                 }
13920         }
13921
13922         /**
13923          * Sniff images
13924          *
13925          * @access private
13926          * @return string Actual Content-Type
13927          */
13928         function image()
13929         {
13930                 if (substr($this->file->body, 0, 6) === 'GIF87a'
13931                         || substr($this->file->body, 0, 6) === 'GIF89a')
13932                 {
13933                         return 'image/gif';
13934                 }
13935                 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
13936                 {
13937                         return 'image/png';
13938                 }
13939                 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
13940                 {
13941                         return 'image/jpeg';
13942                 }
13943                 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
13944                 {
13945                         return 'image/bmp';
13946                 }
13947                 else
13948                 {
13949                         return false;
13950                 }
13951         }
13952
13953         /**
13954          * Sniff HTML
13955          *
13956          * @access private
13957          * @return string Actual Content-Type
13958          */
13959         function feed_or_html()
13960         {
13961                 $len = strlen($this->file->body);
13962                 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
13963
13964                 while ($pos < $len)
13965                 {
13966                         switch ($this->file->body[$pos])
13967                         {
13968                                 case "\x09":
13969                                 case "\x0A":
13970                                 case "\x0D":
13971                                 case "\x20":
13972                                         $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
13973                                         continue 2;
13974
13975                                 case '<':
13976                                         $pos++;
13977                                         break;
13978
13979                                 default:
13980                                         return 'text/html';
13981                         }
13982
13983                         if (substr($this->file->body, $pos, 3) === '!--')
13984                         {
13985                                 $pos += 3;
13986                                 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
13987                                 {
13988                                         $pos += 3;
13989                                 }
13990                                 else
13991                                 {
13992                                         return 'text/html';
13993                                 }
13994                         }
13995                         elseif (substr($this->file->body, $pos, 1) === '!')
13996                         {
13997                                 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
13998                                 {
13999                                         $pos++;
14000                                 }
14001                                 else
14002                                 {
14003                                         return 'text/html';
14004                                 }
14005                         }
14006                         elseif (substr($this->file->body, $pos, 1) === '?')
14007                         {
14008                                 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
14009                                 {
14010                                         $pos += 2;
14011                                 }
14012                                 else
14013                                 {
14014                                         return 'text/html';
14015                                 }
14016                         }
14017                         elseif (substr($this->file->body, $pos, 3) === 'rss'
14018                                 || substr($this->file->body, $pos, 7) === 'rdf:RDF')
14019                         {
14020                                 return 'application/rss+xml';
14021                         }
14022                         elseif (substr($this->file->body, $pos, 4) === 'feed')
14023                         {
14024                                 return 'application/atom+xml';
14025                         }
14026                         else
14027                         {
14028                                 return 'text/html';
14029                         }
14030                 }
14031
14032                 return 'text/html';
14033         }
14034 }
14035
14036 /**
14037  * Parses the XML Declaration
14038  *
14039  * @package SimplePie
14040  */
14041 class SimplePie_XML_Declaration_Parser
14042 {
14043         /**
14044          * XML Version
14045          *
14046          * @access public
14047          * @var string
14048          */
14049         var $version = '1.0';
14050
14051         /**
14052          * Encoding
14053          *
14054          * @access public
14055          * @var string
14056          */
14057         var $encoding = 'UTF-8';
14058
14059         /**
14060          * Standalone
14061          *
14062          * @access public
14063          * @var bool
14064          */
14065         var $standalone = false;
14066
14067         /**
14068          * Current state of the state machine
14069          *
14070          * @access private
14071          * @var string
14072          */
14073         var $state = 'before_version_name';
14074
14075         /**
14076          * Input data
14077          *
14078          * @access private
14079          * @var string
14080          */
14081         var $data = '';
14082
14083         /**
14084          * Input data length (to avoid calling strlen() everytime this is needed)
14085          *
14086          * @access private
14087          * @var int
14088          */
14089         var $data_length = 0;
14090
14091         /**
14092          * Current position of the pointer
14093          *
14094          * @var int
14095          * @access private
14096          */
14097         var $position = 0;
14098
14099         /**
14100          * Create an instance of the class with the input data
14101          *
14102          * @access public
14103          * @param string $data Input data
14104          */
14105         function SimplePie_XML_Declaration_Parser($data)
14106         {
14107                 $this->data = $data;
14108                 $this->data_length = strlen($this->data);
14109         }
14110
14111         /**
14112          * Parse the input data
14113          *
14114          * @access public
14115          * @return bool true on success, false on failure
14116          */
14117         function parse()
14118         {
14119                 while ($this->state && $this->state !== 'emit' && $this->has_data())
14120                 {
14121                         $state = $this->state;
14122                         $this->$state();
14123                 }
14124                 $this->data = '';
14125                 if ($this->state === 'emit')
14126                 {
14127                         return true;
14128                 }
14129                 else
14130                 {
14131                         $this->version = '';
14132                         $this->encoding = '';
14133                         $this->standalone = '';
14134                         return false;
14135                 }
14136         }
14137
14138         /**
14139          * Check whether there is data beyond the pointer
14140          *
14141          * @access private
14142          * @return bool true if there is further data, false if not
14143          */
14144         function has_data()
14145         {
14146                 return (bool) ($this->position < $this->data_length);
14147         }
14148
14149         /**
14150          * Advance past any whitespace
14151          *
14152          * @return int Number of whitespace characters passed
14153          */
14154         function skip_whitespace()
14155         {
14156                 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
14157                 $this->position += $whitespace;
14158                 return $whitespace;
14159         }
14160
14161         /**
14162          * Read value
14163          */
14164         function get_value()
14165         {
14166                 $quote = substr($this->data, $this->position, 1);
14167                 if ($quote === '"' || $quote === "'")
14168                 {
14169                         $this->position++;
14170                         $len = strcspn($this->data, $quote, $this->position);
14171                         if ($this->has_data())
14172                         {
14173                                 $value = substr($this->data, $this->position, $len);
14174                                 $this->position += $len + 1;
14175                                 return $value;
14176                         }
14177                 }
14178                 return false;
14179         }
14180
14181         function before_version_name()
14182         {
14183                 if ($this->skip_whitespace())
14184                 {
14185                         $this->state = 'version_name';
14186                 }
14187                 else
14188                 {
14189                         $this->state = false;
14190                 }
14191         }
14192
14193         function version_name()
14194         {
14195                 if (substr($this->data, $this->position, 7) === 'version')
14196                 {
14197                         $this->position += 7;
14198                         $this->skip_whitespace();
14199                         $this->state = 'version_equals';
14200                 }
14201                 else
14202                 {
14203                         $this->state = false;
14204                 }
14205         }
14206
14207         function version_equals()
14208         {
14209                 if (substr($this->data, $this->position, 1) === '=')
14210                 {
14211                         $this->position++;
14212                         $this->skip_whitespace();
14213                         $this->state = 'version_value';
14214                 }
14215                 else
14216                 {
14217                         $this->state = false;
14218                 }
14219         }
14220
14221         function version_value()
14222         {
14223                 if ($this->version = $this->get_value())
14224                 {
14225                         $this->skip_whitespace();
14226                         if ($this->has_data())
14227                         {
14228                                 $this->state = 'encoding_name';
14229                         }
14230                         else
14231                         {
14232                                 $this->state = 'emit';
14233                         }
14234                 }
14235                 else
14236                 {
14237                         $this->state = false;
14238                 }
14239         }
14240
14241         function encoding_name()
14242         {
14243                 if (substr($this->data, $this->position, 8) === 'encoding')
14244                 {
14245                         $this->position += 8;
14246                         $this->skip_whitespace();
14247                         $this->state = 'encoding_equals';
14248                 }
14249                 else
14250                 {
14251                         $this->state = 'standalone_name';
14252                 }
14253         }
14254
14255         function encoding_equals()
14256         {
14257                 if (substr($this->data, $this->position, 1) === '=')
14258                 {
14259                         $this->position++;
14260                         $this->skip_whitespace();
14261                         $this->state = 'encoding_value';
14262                 }
14263                 else
14264                 {
14265                         $this->state = false;
14266                 }
14267         }
14268
14269         function encoding_value()
14270         {
14271                 if ($this->encoding = $this->get_value())
14272                 {
14273                         $this->skip_whitespace();
14274                         if ($this->has_data())
14275                         {
14276                                 $this->state = 'standalone_name';
14277                         }
14278                         else
14279                         {
14280                                 $this->state = 'emit';
14281                         }
14282                 }
14283                 else
14284                 {
14285                         $this->state = false;
14286                 }
14287         }
14288
14289         function standalone_name()
14290         {
14291                 if (substr($this->data, $this->position, 10) === 'standalone')
14292                 {
14293                         $this->position += 10;
14294                         $this->skip_whitespace();
14295                         $this->state = 'standalone_equals';
14296                 }
14297                 else
14298                 {
14299                         $this->state = false;
14300                 }
14301         }
14302
14303         function standalone_equals()
14304         {
14305                 if (substr($this->data, $this->position, 1) === '=')
14306                 {
14307                         $this->position++;
14308                         $this->skip_whitespace();
14309                         $this->state = 'standalone_value';
14310                 }
14311                 else
14312                 {
14313                         $this->state = false;
14314                 }
14315         }
14316
14317         function standalone_value()
14318         {
14319                 if ($standalone = $this->get_value())
14320                 {
14321                         switch ($standalone)
14322                         {
14323                                 case 'yes':
14324                                         $this->standalone = true;
14325                                         break;
14326
14327                                 case 'no':
14328                                         $this->standalone = false;
14329                                         break;
14330
14331                                 default:
14332                                         $this->state = false;
14333                                         return;
14334                         }
14335
14336                         $this->skip_whitespace();
14337                         if ($this->has_data())
14338                         {
14339                                 $this->state = false;
14340                         }
14341                         else
14342                         {
14343                                 $this->state = 'emit';
14344                         }
14345                 }
14346                 else
14347                 {
14348                         $this->state = false;
14349                 }
14350         }
14351 }
14352
14353 class SimplePie_Locator
14354 {
14355         var $useragent;
14356         var $timeout;
14357         var $file;
14358         var $local = array();
14359         var $elsewhere = array();
14360         var $file_class = 'SimplePie_File';
14361         var $cached_entities = array();
14362         var $http_base;
14363         var $base;
14364         var $base_location = 0;
14365         var $checked_feeds = 0;
14366         var $max_checked_feeds = 10;
14367         var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
14368
14369         function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer')
14370         {
14371                 $this->file =& $file;
14372                 $this->file_class = $file_class;
14373                 $this->useragent = $useragent;
14374                 $this->timeout = $timeout;
14375                 $this->max_checked_feeds = $max_checked_feeds;
14376                 $this->content_type_sniffer_class = $content_type_sniffer_class;
14377         }
14378
14379         function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
14380         {
14381                 if ($this->is_feed($this->file))
14382                 {
14383                         return $this->file;
14384                 }
14385
14386                 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
14387                 {
14388                         $sniffer =& new $this->content_type_sniffer_class($this->file);
14389                         if ($sniffer->get_type() !== 'text/html')
14390                         {
14391                                 return null;
14392                         }
14393                 }
14394
14395                 if ($type & ~SIMPLEPIE_LOCATOR_NONE)
14396                 {
14397                         $this->get_base();
14398                 }
14399
14400                 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
14401                 {
14402                         return $working[0];
14403                 }
14404
14405                 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
14406                 {
14407                         if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
14408                         {
14409                                 return $working;
14410                         }
14411
14412                         if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
14413                         {
14414                                 return $working;
14415                         }
14416
14417                         if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
14418                         {
14419                                 return $working;
14420                         }
14421
14422                         if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
14423                         {
14424                                 return $working;
14425                         }
14426                 }
14427                 return null;
14428         }
14429
14430         function is_feed(&$file)
14431         {
14432                 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
14433                 {
14434                         $sniffer =& new $this->content_type_sniffer_class($file);
14435                         $sniffed = $sniffer->get_type();
14436                         if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
14437                         {
14438                                 return true;
14439                         }
14440                         else
14441                         {
14442                                 return false;
14443                         }
14444                 }
14445                 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
14446                 {
14447                         return true;
14448                 }
14449                 else
14450                 {
14451                         return false;
14452                 }
14453         }
14454
14455         function get_base()
14456         {
14457                 $this->http_base = $this->file->url;
14458                 $this->base = $this->http_base;
14459                 $elements = SimplePie_Misc::get_element('base', $this->file->body);
14460                 foreach ($elements as $element)
14461                 {
14462                         if ($element['attribs']['href']['data'] !== '')
14463                         {
14464                                 $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base);
14465                                 $this->base_location = $element['offset'];
14466                                 break;
14467                         }
14468                 }
14469         }
14470
14471         function autodiscovery()
14472         {
14473                 $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body));
14474                 $done = array();
14475                 $feeds = array();
14476                 foreach ($links as $link)
14477                 {
14478                         if ($this->checked_feeds === $this->max_checked_feeds)
14479                         {
14480                                 break;
14481                         }
14482                         if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data']))
14483                         {
14484                                 $rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data'])));
14485
14486                                 if ($this->base_location < $link['offset'])
14487                                 {
14488                                         $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
14489                                 }
14490                                 else
14491                                 {
14492                                         $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
14493                                 }
14494
14495                                 if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
14496                                 {
14497                                         $this->checked_feeds++;
14498                                         $feed =& new $this->file_class($href, $this->timeout, 5, null, $this->useragent);
14499                                         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))
14500                                         {
14501                                                 $feeds[$href] = $feed;
14502                                         }
14503                                 }
14504                                 $done[] = $href;
14505                         }
14506                 }
14507
14508                 if (!empty($feeds))
14509                 {
14510                         return array_values($feeds);
14511                 }
14512                 else {
14513                         return null;
14514                 }
14515         }
14516
14517         function get_links()
14518         {
14519                 $links = SimplePie_Misc::get_element('a', $this->file->body);
14520                 foreach ($links as $link)
14521                 {
14522                         if (isset($link['attribs']['href']['data']))
14523                         {
14524                                 $href = trim($link['attribs']['href']['data']);
14525                                 $parsed = SimplePie_Misc::parse_url($href);
14526                                 if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
14527                                 {
14528                                         if ($this->base_location < $link['offset'])
14529                                         {
14530                                                 $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
14531                                         }
14532                                         else
14533                                         {
14534                                                 $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
14535                                         }
14536
14537                                         $current = SimplePie_Misc::parse_url($this->file->url);
14538
14539                                         if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
14540                                         {
14541                                                 $this->local[] = $href;
14542                                         }
14543                                         else
14544                                         {
14545                                                 $this->elsewhere[] = $href;
14546                                         }
14547                                 }
14548                         }
14549                 }
14550                 $this->local = array_unique($this->local);
14551                 $this->elsewhere = array_unique($this->elsewhere);
14552                 if (!empty($this->local) || !empty($this->elsewhere))
14553                 {
14554                         return true;
14555                 }
14556                 return null;
14557         }
14558
14559         function extension(&$array)
14560         {
14561                 foreach ($array as $key => $value)
14562                 {
14563                         if ($this->checked_feeds === $this->max_checked_feeds)
14564                         {
14565                                 break;
14566                         }
14567                         if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
14568                         {
14569                                 $this->checked_feeds++;
14570                                 $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
14571                                 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))
14572                                 {
14573                                         return $feed;
14574                                 }
14575                                 else
14576                                 {
14577                                         unset($array[$key]);
14578                                 }
14579                         }
14580                 }
14581                 return null;
14582         }
14583
14584         function body(&$array)
14585         {
14586                 foreach ($array as $key => $value)
14587                 {
14588                         if ($this->checked_feeds === $this->max_checked_feeds)
14589                         {
14590                                 break;
14591                         }
14592                         if (preg_match('/(rss|rdf|atom|xml)/i', $value))
14593                         {
14594                                 $this->checked_feeds++;
14595                                 $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
14596                                 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))
14597                                 {
14598                                         return $feed;
14599                                 }
14600                                 else
14601                                 {
14602                                         unset($array[$key]);
14603                                 }
14604                         }
14605                 }
14606                 return null;
14607         }
14608 }
14609
14610 class SimplePie_Parser
14611 {
14612         var $error_code;
14613         var $error_string;
14614         var $current_line;
14615         var $current_column;
14616         var $current_byte;
14617         var $separator = ' ';
14618         var $namespace = array('');
14619         var $element = array('');
14620         var $xml_base = array('');
14621         var $xml_base_explicit = array(false);
14622         var $xml_lang = array('');
14623         var $data = array();
14624         var $datas = array(array());
14625         var $current_xhtml_construct = -1;
14626         var $encoding;
14627
14628         function parse(&$data, $encoding)
14629         {
14630                 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
14631                 if (strtoupper($encoding) === 'US-ASCII')
14632                 {
14633                         $this->encoding = 'UTF-8';
14634                 }
14635                 else
14636                 {
14637                         $this->encoding = $encoding;
14638                 }
14639
14640                 // Strip BOM:
14641                 // UTF-32 Big Endian BOM
14642                 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
14643                 {
14644                         $data = substr($data, 4);
14645                 }
14646                 // UTF-32 Little Endian BOM
14647                 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
14648                 {
14649                         $data = substr($data, 4);
14650                 }
14651                 // UTF-16 Big Endian BOM
14652                 elseif (substr($data, 0, 2) === "\xFE\xFF")
14653                 {
14654                         $data = substr($data, 2);
14655                 }
14656                 // UTF-16 Little Endian BOM
14657                 elseif (substr($data, 0, 2) === "\xFF\xFE")
14658                 {
14659                         $data = substr($data, 2);
14660                 }
14661                 // UTF-8 BOM
14662                 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
14663                 {
14664                         $data = substr($data, 3);
14665                 }
14666
14667                 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
14668                 {
14669                         $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
14670                         if ($declaration->parse())
14671                         {
14672                                 $data = substr($data, $pos + 2);
14673                                 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
14674                         }
14675                         else
14676                         {
14677                                 $this->error_string = 'SimplePie bug! Please report this!';
14678                                 return false;
14679                         }
14680                 }
14681
14682                 $return = true;
14683
14684                 static $xml_is_sane = null;
14685                 if ($xml_is_sane === null)
14686                 {
14687                         $parser_check = xml_parser_create();
14688                         xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
14689                         xml_parser_free($parser_check);
14690                         $xml_is_sane = isset($values[0]['value']);
14691                 }
14692
14693                 // Create the parser
14694                 if ($xml_is_sane)
14695                 {
14696                         $xml = xml_parser_create_ns($this->encoding, $this->separator);
14697                         xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
14698                         xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
14699                         xml_set_object($xml, $this);
14700                         xml_set_character_data_handler($xml, 'cdata');
14701                         xml_set_element_handler($xml, 'tag_open', 'tag_close');
14702
14703                         // Parse!
14704                         if (!xml_parse($xml, $data, true))
14705                         {
14706                                 $this->error_code = xml_get_error_code($xml);
14707                                 $this->error_string = xml_error_string($this->error_code);
14708                                 $return = false;
14709                         }
14710                         $this->current_line = xml_get_current_line_number($xml);
14711                         $this->current_column = xml_get_current_column_number($xml);
14712                         $this->current_byte = xml_get_current_byte_index($xml);
14713                         xml_parser_free($xml);
14714                         return $return;
14715                 }
14716                 else
14717                 {
14718                         libxml_clear_errors();
14719                         $xml =& new XMLReader();
14720                         $xml->xml($data);
14721                         while (@$xml->read())
14722                         {
14723                                 switch ($xml->nodeType)
14724                                 {
14725
14726                                         case constant('XMLReader::END_ELEMENT'):
14727                                                 if ($xml->namespaceURI !== '')
14728                                                 {
14729                                                         $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
14730                                                 }
14731                                                 else
14732                                                 {
14733                                                         $tagName = $xml->localName;
14734                                                 }
14735                                                 $this->tag_close(null, $tagName);
14736                                                 break;
14737                                         case constant('XMLReader::ELEMENT'):
14738                                                 $empty = $xml->isEmptyElement;
14739                                                 if ($xml->namespaceURI !== '')
14740                                                 {
14741                                                         $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
14742                                                 }
14743                                                 else
14744                                                 {
14745                                                         $tagName = $xml->localName;
14746                                                 }
14747                                                 $attributes = array();
14748                                                 while ($xml->moveToNextAttribute())
14749                                                 {
14750                                                         if ($xml->namespaceURI !== '')
14751                                                         {
14752                                                                 $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
14753                                                         }
14754                                                         else
14755                                                         {
14756                                                                 $attrName = $xml->localName;
14757                                                         }
14758                                                         $attributes[$attrName] = $xml->value;
14759                                                 }
14760                                                 $this->tag_open(null, $tagName, $attributes);
14761                                                 if ($empty)
14762                                                 {
14763                                                         $this->tag_close(null, $tagName);
14764                                                 }
14765                                                 break;
14766                                         case constant('XMLReader::TEXT'):
14767
14768                                         case constant('XMLReader::CDATA'):
14769                                                 $this->cdata(null, $xml->value);
14770                                                 break;
14771                                 }
14772                         }
14773                         if ($error = libxml_get_last_error())
14774                         {
14775                                 $this->error_code = $error->code;
14776                                 $this->error_string = $error->message;
14777                                 $this->current_line = $error->line;
14778                                 $this->current_column = $error->column;
14779                                 return false;
14780                         }
14781                         else
14782                         {
14783                                 return true;
14784                         }
14785                 }
14786         }
14787
14788         function get_error_code()
14789         {
14790                 return $this->error_code;
14791         }
14792
14793         function get_error_string()
14794         {
14795                 return $this->error_string;
14796         }
14797
14798         function get_current_line()
14799         {
14800                 return $this->current_line;
14801         }
14802
14803         function get_current_column()
14804         {
14805                 return $this->current_column;
14806         }
14807
14808         function get_current_byte()
14809         {
14810                 return $this->current_byte;
14811         }
14812
14813         function get_data()
14814         {
14815                 return $this->data;
14816         }
14817
14818         function tag_open($parser, $tag, $attributes)
14819         {
14820                 list($this->namespace[], $this->element[]) = $this->split_ns($tag);
14821
14822                 $attribs = array();
14823                 foreach ($attributes as $name => $value)
14824                 {
14825                         list($attrib_namespace, $attribute) = $this->split_ns($name);
14826                         $attribs[$attrib_namespace][$attribute] = $value;
14827                 }
14828
14829                 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
14830                 {
14831                         $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base));
14832                         $this->xml_base_explicit[] = true;
14833                 }
14834                 else
14835                 {
14836                         $this->xml_base[] = end($this->xml_base);
14837                         $this->xml_base_explicit[] = end($this->xml_base_explicit);
14838                 }
14839
14840                 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
14841                 {
14842                         $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
14843                 }
14844                 else
14845                 {
14846                         $this->xml_lang[] = end($this->xml_lang);
14847                 }
14848
14849                 if ($this->current_xhtml_construct >= 0)
14850                 {
14851                         $this->current_xhtml_construct++;
14852                         if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
14853                         {
14854                                 $this->data['data'] .= '<' . end($this->element);
14855                                 if (isset($attribs['']))
14856                                 {
14857                                         foreach ($attribs[''] as $name => $value)
14858                                         {
14859                                                 $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
14860                                         }
14861                                 }
14862                                 $this->data['data'] .= '>';
14863                         }
14864                 }
14865                 else
14866                 {
14867                         $this->datas[] =& $this->data;
14868                         $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
14869                         $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));
14870                         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')
14871                         || (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'))
14872                         {
14873                                 $this->current_xhtml_construct = 0;
14874                         }
14875                 }
14876         }
14877
14878         function cdata($parser, $cdata)
14879         {
14880                 if ($this->current_xhtml_construct >= 0)
14881                 {
14882                         $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
14883                 }
14884                 else
14885                 {
14886                         $this->data['data'] .= $cdata;
14887                 }
14888         }
14889
14890         function tag_close($parser, $tag)
14891         {
14892                 if ($this->current_xhtml_construct >= 0)
14893                 {
14894                         $this->current_xhtml_construct--;
14895                         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')))
14896                         {
14897                                 $this->data['data'] .= '</' . end($this->element) . '>';
14898                         }
14899                 }
14900                 if ($this->current_xhtml_construct === -1)
14901                 {
14902                         $this->data =& $this->datas[count($this->datas) - 1];
14903                         array_pop($this->datas);
14904                 }
14905
14906                 array_pop($this->element);
14907                 array_pop($this->namespace);
14908                 array_pop($this->xml_base);
14909                 array_pop($this->xml_base_explicit);
14910                 array_pop($this->xml_lang);
14911         }
14912
14913         function split_ns($string)
14914         {
14915                 static $cache = array();
14916                 if (!isset($cache[$string]))
14917                 {
14918                         if ($pos = strpos($string, $this->separator))
14919                         {
14920                                 static $separator_length;
14921                                 if (!$separator_length)
14922                                 {
14923                                         $separator_length = strlen($this->separator);
14924                                 }
14925                                 $namespace = substr($string, 0, $pos);
14926                                 $local_name = substr($string, $pos + $separator_length);
14927                                 if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
14928                                 {
14929                                         $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
14930                                 }
14931
14932                                 // Normalize the Media RSS namespaces
14933                                 if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG)
14934                                 {
14935                                         $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
14936                                 }
14937                                 $cache[$string] = array($namespace, $local_name);
14938                         }
14939                         else
14940                         {
14941                                 $cache[$string] = array('', $string);
14942                         }
14943                 }
14944                 return $cache[$string];
14945         }
14946 }
14947
14948 /**
14949  * @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
14950  */
14951 class SimplePie_Sanitize
14952 {
14953         // Private vars
14954         var $base;
14955
14956         // Options
14957         var $remove_div = true;
14958         var $image_handler = '';
14959         var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
14960         var $encode_instead_of_strip = false;
14961         var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
14962         var $strip_comments = false;
14963         var $output_encoding = 'UTF-8';
14964         var $enable_cache = true;
14965         var $cache_location = './cache';
14966         var $cache_name_function = 'md5';
14967         var $cache_class = 'SimplePie_Cache';
14968         var $file_class = 'SimplePie_File';
14969         var $timeout = 10;
14970         var $useragent = '';
14971         var $force_fsockopen = false;
14972
14973         var $replace_url_attributes = array(
14974                 'a' => 'href',
14975                 'area' => 'href',
14976                 'blockquote' => 'cite',
14977                 'del' => 'cite',
14978                 'form' => 'action',
14979                 'img' => array('longdesc', 'src'),
14980                 'input' => 'src',
14981                 'ins' => 'cite',
14982                 'q' => 'cite'
14983         );
14984
14985         function remove_div($enable = true)
14986         {
14987                 $this->remove_div = (bool) $enable;
14988         }
14989
14990         function set_image_handler($page = false)
14991         {
14992                 if ($page)
14993                 {
14994                         $this->image_handler = (string) $page;
14995                 }
14996                 else
14997                 {
14998                         $this->image_handler = false;
14999                 }
15000         }
15001
15002         function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
15003         {
15004                 if (isset($enable_cache))
15005                 {
15006                         $this->enable_cache = (bool) $enable_cache;
15007                 }
15008
15009                 if ($cache_location)
15010                 {
15011                         $this->cache_location = (string) $cache_location;
15012                 }
15013
15014                 if ($cache_name_function)
15015                 {
15016                         $this->cache_name_function = (string) $cache_name_function;
15017                 }
15018
15019                 if ($cache_class)
15020                 {
15021                         $this->cache_class = (string) $cache_class;
15022                 }
15023         }
15024
15025         function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
15026         {
15027                 if ($file_class)
15028                 {
15029                         $this->file_class = (string) $file_class;
15030                 }
15031
15032                 if ($timeout)
15033                 {
15034                         $this->timeout = (string) $timeout;
15035                 }
15036
15037                 if ($useragent)
15038                 {
15039                         $this->useragent = (string) $useragent;
15040                 }
15041
15042                 if ($force_fsockopen)
15043                 {
15044                         $this->force_fsockopen = (string) $force_fsockopen;
15045                 }
15046         }
15047
15048         function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
15049         {
15050                 if ($tags)
15051                 {
15052                         if (is_array($tags))
15053                         {
15054                                 $this->strip_htmltags = $tags;
15055                         }
15056                         else
15057                         {
15058                                 $this->strip_htmltags = explode(',', $tags);
15059                         }
15060                 }
15061                 else
15062                 {
15063                         $this->strip_htmltags = false;
15064                 }
15065         }
15066
15067         function encode_instead_of_strip($encode = false)
15068         {
15069                 $this->encode_instead_of_strip = (bool) $encode;
15070         }
15071
15072         function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
15073         {
15074                 if ($attribs)
15075                 {
15076                         if (is_array($attribs))
15077                         {
15078                                 $this->strip_attributes = $attribs;
15079                         }
15080                         else
15081                         {
15082                                 $this->strip_attributes = explode(',', $attribs);
15083                         }
15084                 }
15085                 else
15086                 {
15087                         $this->strip_attributes = false;
15088                 }
15089         }
15090
15091         function strip_comments($strip = false)
15092         {
15093                 $this->strip_comments = (bool) $strip;
15094         }
15095
15096         function set_output_encoding($encoding = 'UTF-8')
15097         {
15098                 $this->output_encoding = (string) $encoding;
15099         }
15100
15101         /**
15102          * Set element/attribute key/value pairs of HTML attributes
15103          * containing URLs that need to be resolved relative to the feed
15104          *
15105          * @access public
15106          * @since 1.0
15107          * @param array $element_attribute Element/attribute key/value pairs
15108          */
15109         function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
15110         {
15111                 $this->replace_url_attributes = (array) $element_attribute;
15112         }
15113
15114         function sanitize($data, $type, $base = '')
15115         {
15116                 $data = trim($data);
15117                 if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
15118                 {
15119                         if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
15120                         {
15121                                 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))
15122                                 {
15123                                         $type |= SIMPLEPIE_CONSTRUCT_HTML;
15124                                 }
15125                                 else
15126                                 {
15127                                         $type |= SIMPLEPIE_CONSTRUCT_TEXT;
15128                                 }
15129                         }
15130
15131                         if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
15132                         {
15133                                 $data = base64_decode($data);
15134                         }
15135
15136                         if ($type & SIMPLEPIE_CONSTRUCT_XHTML)
15137                         {
15138                                 if ($this->remove_div)
15139                                 {
15140                                         $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
15141                                         $data = preg_replace('/<\/div>$/', '', $data);
15142                                 }
15143                                 else
15144                                 {
15145                                         $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
15146                                 }
15147                         }
15148
15149                         if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
15150                         {
15151                                 // Strip comments
15152                                 if ($this->strip_comments)
15153                                 {
15154                                         $data = SimplePie_Misc::strip_comments($data);
15155                                 }
15156
15157                                 // Strip out HTML tags and attributes that might cause various security problems.
15158                                 // Based on recommendations by Mark Pilgrim at:
15159                                 // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
15160                                 if ($this->strip_htmltags)
15161                                 {
15162                                         foreach ($this->strip_htmltags as $tag)
15163                                         {
15164                                                 $pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU';
15165                                                 while (preg_match($pcre, $data))
15166                                                 {
15167                                                         $data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data);
15168                                                 }
15169                                         }
15170                                 }
15171
15172                                 if ($this->strip_attributes)
15173                                 {
15174                                         foreach ($this->strip_attributes as $attrib)
15175                                         {
15176                                                 $data = preg_replace('/(<[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . trim($attrib) . '(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>/', '\1\2\3>', $data);
15177                                         }
15178                                 }
15179
15180                                 // Replace relative URLs
15181                                 $this->base = $base;
15182                                 foreach ($this->replace_url_attributes as $element => $attributes)
15183                                 {
15184                                         $data = $this->replace_urls($data, $element, $attributes);
15185                                 }
15186
15187                                 // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
15188                                 if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
15189                                 {
15190                                         $images = SimplePie_Misc::get_element('img', $data);
15191                                         foreach ($images as $img)
15192                                         {
15193                                                 if (isset($img['attribs']['src']['data']))
15194                                                 {
15195                                                         $image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']);
15196                                                         $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi');
15197
15198                                                         if ($cache->load())
15199                                                         {
15200                                                                 $img['attribs']['src']['data'] = $this->image_handler . $image_url;
15201                                                                 $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
15202                                                         }
15203                                                         else
15204                                                         {
15205                                                                 $file =& new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
15206                                                                 $headers = $file->headers;
15207
15208                                                                 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
15209                                                                 {
15210                                                                         if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
15211                                                                         {
15212                                                                                 $img['attribs']['src']['data'] = $this->image_handler . $image_url;
15213                                                                                 $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
15214                                                                         }
15215                                                                         else
15216                                                                         {
15217                                                                                 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);
15218                                                                         }
15219                                                                 }
15220                                                         }
15221                                                 }
15222                                         }
15223                                 }
15224
15225                                 // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data
15226                                 $data = trim($data);
15227                         }
15228
15229                         if ($type & SIMPLEPIE_CONSTRUCT_IRI)
15230                         {
15231                                 $data = SimplePie_Misc::absolutize_url($data, $base);
15232                         }
15233
15234                         if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
15235                         {
15236                                 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
15237                         }
15238
15239                         if ($this->output_encoding !== 'UTF-8')
15240                         {
15241                                 $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding);
15242                         }
15243                 }
15244                 return $data;
15245         }
15246
15247         function replace_urls($data, $tag, $attributes)
15248         {
15249                 if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
15250                 {
15251                         $elements = SimplePie_Misc::get_element($tag, $data);
15252                         foreach ($elements as $element)
15253                         {
15254                                 if (is_array($attributes))
15255                                 {
15256                                         foreach ($attributes as $attribute)
15257                                         {
15258                                                 if (isset($element['attribs'][$attribute]['data']))
15259                                                 {
15260                                                         $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base);
15261                                                         $new_element = SimplePie_Misc::element_implode($element);
15262                                                         $data = str_replace($element['full'], $new_element, $data);
15263                                                         $element['full'] = $new_element;
15264                                                 }
15265                                         }
15266                                 }
15267                                 elseif (isset($element['attribs'][$attributes]['data']))
15268                                 {
15269                                         $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base);
15270                                         $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data);
15271                                 }
15272                         }
15273                 }
15274                 return $data;
15275         }
15276
15277         function do_strip_htmltags($match)
15278         {
15279                 if ($this->encode_instead_of_strip)
15280                 {
15281                         if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
15282                         {
15283                                 $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
15284                                 $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
15285                                 return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
15286                         }
15287                         else
15288                         {
15289                                 return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
15290                         }
15291                 }
15292                 elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
15293                 {
15294                         return $match[4];
15295                 }
15296                 else
15297                 {
15298                         return '';
15299                 }
15300         }
15301 }
15302
15303 ?>