]> git.immae.eu Git - github/wallabag/wallabag.git/blob - inc/3rdparty/simplepie/SimplePie/Core.php
Merge pull request #181 from inthepoche/dev
[github/wallabag/wallabag.git] / inc / 3rdparty / simplepie / SimplePie / Core.php
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-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3-dev
37 * @copyright 2004-2010 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 * @todo phpDoc comments
44 */
45
46 /**
47 * SimplePie Name
48 */
49 define('SIMPLEPIE_NAME', 'SimplePie');
50
51 /**
52 * SimplePie Version
53 */
54 define('SIMPLEPIE_VERSION', '1.3-dev');
55
56 /**
57 * SimplePie Build
58 * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
59 */
60 define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::get_build()));
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. Caused by a long-standing typo in the spec.
338 */
339 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
340
341 /**
342 * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
343 */
344 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
345
346 /**
347 * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
348 */
349 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
350
351 /**
352 * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
353 */
354 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
355
356 /**
357 * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
358 */
359 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
360
361 /**
362 * iTunes RSS Namespace
363 */
364 define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
365
366 /**
367 * XHTML Namespace
368 */
369 define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
370
371 /**
372 * IANA Link Relations Registry
373 */
374 define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
375
376 /**
377 * Whether we're running on PHP5
378 */
379 define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>='));
380
381 /**
382 * No file source
383 */
384 define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
385
386 /**
387 * Remote file source
388 */
389 define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
390
391 /**
392 * Local file source
393 */
394 define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
395
396 /**
397 * fsockopen() file source
398 */
399 define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
400
401 /**
402 * cURL file source
403 */
404 define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
405
406 /**
407 * file_get_contents() file source
408 */
409 define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
410
411
412
413 /**
414 * SimplePie
415 *
416 * @package SimplePie
417 */
418 class SimplePie_Core
419 {
420 /**
421 * @var array Raw data
422 * @access private
423 */
424 public $data = array();
425
426 /**
427 * @var mixed Error string
428 * @access private
429 */
430 public $error;
431
432 /**
433 * @var object Instance of SimplePie_Sanitize (or other class)
434 * @see SimplePie::set_sanitize_class()
435 * @access private
436 */
437 public $sanitize;
438
439 /**
440 * @var string SimplePie Useragent
441 * @see SimplePie::set_useragent()
442 * @access private
443 */
444 public $useragent = SIMPLEPIE_USERAGENT;
445
446 /**
447 * @var string Feed URL
448 * @see SimplePie::set_feed_url()
449 * @access private
450 */
451 public $feed_url;
452
453 /**
454 * @var object Instance of SimplePie_File to use as a feed
455 * @see SimplePie::set_file()
456 * @access private
457 */
458 public $file;
459
460 /**
461 * @var string Raw feed data
462 * @see SimplePie::set_raw_data()
463 * @access private
464 */
465 public $raw_data;
466
467 /**
468 * @var int Timeout for fetching remote files
469 * @see SimplePie::set_timeout()
470 * @access private
471 */
472 public $timeout = 10;
473
474 /**
475 * @var bool Forces fsockopen() to be used for remote files instead
476 * of cURL, even if a new enough version is installed
477 * @see SimplePie::force_fsockopen()
478 * @access private
479 */
480 public $force_fsockopen = false;
481
482 /**
483 * @var bool Force the given data/URL to be treated as a feed no matter what
484 * it appears like
485 * @see SimplePie::force_feed()
486 * @access private
487 */
488 public $force_feed = false;
489
490 /**
491 * @var bool Enable/Disable XML dump
492 * @see SimplePie::enable_xml_dump()
493 * @access private
494 */
495 public $xml_dump = false;
496
497 /**
498 * @var bool Enable/Disable Caching
499 * @see SimplePie::enable_cache()
500 * @access private
501 */
502 public $cache = true;
503
504 /**
505 * @var int Cache duration (in seconds)
506 * @see SimplePie::set_cache_duration()
507 * @access private
508 */
509 public $cache_duration = 3600;
510
511 /**
512 * @var int Auto-discovery cache duration (in seconds)
513 * @see SimplePie::set_autodiscovery_cache_duration()
514 * @access private
515 */
516 public $autodiscovery_cache_duration = 604800; // 7 Days.
517
518 /**
519 * @var string Cache location (relative to executing script)
520 * @see SimplePie::set_cache_location()
521 * @access private
522 */
523 public $cache_location = './cache';
524
525 /**
526 * @var string Function that creates the cache filename
527 * @see SimplePie::set_cache_name_function()
528 * @access private
529 */
530 public $cache_name_function = 'md5';
531
532 /**
533 * @var bool Reorder feed by date descending
534 * @see SimplePie::enable_order_by_date()
535 * @access private
536 */
537 public $order_by_date = true;
538
539 /**
540 * @var mixed Force input encoding to be set to the follow value
541 * (false, or anything type-cast to false, disables this feature)
542 * @see SimplePie::set_input_encoding()
543 * @access private
544 */
545 public $input_encoding = false;
546
547 /**
548 * @var int Feed Autodiscovery Level
549 * @see SimplePie::set_autodiscovery_level()
550 * @access private
551 */
552 public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
553
554 /**
555 * @var string Class used for caching feeds
556 * @see SimplePie::set_cache_class()
557 * @access private
558 */
559 public $cache_class = 'SimplePie_Cache';
560
561 /**
562 * @var string Class used for locating feeds
563 * @see SimplePie::set_locator_class()
564 * @access private
565 */
566 public $locator_class = 'SimplePie_Locator';
567
568 /**
569 * @var string Class used for parsing feeds
570 * @see SimplePie::set_parser_class()
571 * @access private
572 */
573 public $parser_class = 'SimplePie_Parser';
574
575 /**
576 * @var string Class used for fetching feeds
577 * @see SimplePie::set_file_class()
578 * @access private
579 */
580 public $file_class = 'SimplePie_File';
581
582 /**
583 * @var string Class used for items
584 * @see SimplePie::set_item_class()
585 * @access private
586 */
587 public $item_class = 'SimplePie_Item';
588
589 /**
590 * @var string Class used for authors
591 * @see SimplePie::set_author_class()
592 * @access private
593 */
594 public $author_class = 'SimplePie_Author';
595
596 /**
597 * @var string Class used for categories
598 * @see SimplePie::set_category_class()
599 * @access private
600 */
601 public $category_class = 'SimplePie_Category';
602
603 /**
604 * @var string Class used for enclosures
605 * @see SimplePie::set_enclosures_class()
606 * @access private
607 */
608 public $enclosure_class = 'SimplePie_Enclosure';
609
610 /**
611 * @var string Class used for Media RSS <media:text> captions
612 * @see SimplePie::set_caption_class()
613 * @access private
614 */
615 public $caption_class = 'SimplePie_Caption';
616
617 /**
618 * @var string Class used for Media RSS <media:copyright>
619 * @see SimplePie::set_copyright_class()
620 * @access private
621 */
622 public $copyright_class = 'SimplePie_Copyright';
623
624 /**
625 * @var string Class used for Media RSS <media:credit>
626 * @see SimplePie::set_credit_class()
627 * @access private
628 */
629 public $credit_class = 'SimplePie_Credit';
630
631 /**
632 * @var string Class used for Media RSS <media:rating>
633 * @see SimplePie::set_rating_class()
634 * @access private
635 */
636 public $rating_class = 'SimplePie_Rating';
637
638 /**
639 * @var string Class used for Media RSS <media:restriction>
640 * @see SimplePie::set_restriction_class()
641 * @access private
642 */
643 public $restriction_class = 'SimplePie_Restriction';
644
645 /**
646 * @var string Class used for content-type sniffing
647 * @see SimplePie::set_content_type_sniffer_class()
648 * @access private
649 */
650 public $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
651
652 /**
653 * @var string Class used for item sources.
654 * @see SimplePie::set_source_class()
655 * @access private
656 */
657 public $source_class = 'SimplePie_Source';
658
659 /**
660 * @var int Maximum number of feeds to check with autodiscovery
661 * @see SimplePie::set_max_checked_feeds()
662 * @access private
663 */
664 public $max_checked_feeds = 10;
665
666 /**
667 * @var array All the feeds found during the autodiscovery process
668 * @see SimplePie::get_all_discovered_feeds()
669 * @access private
670 */
671 public $all_discovered_feeds = array();
672
673 /**
674 * @var string Web-accessible path to the handler_image.php file.
675 * @see SimplePie::set_image_handler()
676 * @access private
677 */
678 public $image_handler = '';
679
680 /**
681 * @var array Stores the URLs when multiple feeds are being initialized.
682 * @see SimplePie::set_feed_url()
683 * @access private
684 */
685 public $multifeed_url = array();
686
687 /**
688 * @var array Stores SimplePie objects when multiple feeds initialized.
689 * @access private
690 */
691 public $multifeed_objects = array();
692
693 /**
694 * @var array Stores the get_object_vars() array for use with multifeeds.
695 * @see SimplePie::set_feed_url()
696 * @access private
697 */
698 public $config_settings = null;
699
700 /**
701 * @var integer Stores the number of items to return per-feed with multifeeds.
702 * @see SimplePie::set_item_limit()
703 * @access private
704 */
705 public $item_limit = 0;
706
707 /**
708 * @var array Stores the default attributes to be stripped by strip_attributes().
709 * @see SimplePie::strip_attributes()
710 * @access private
711 */
712 public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
713
714 /**
715 * @var array Stores the default tags to be stripped by strip_htmltags().
716 * @see SimplePie::strip_htmltags()
717 * @access private
718 */
719 public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
720
721 /**
722 * The SimplePie class contains feed level data and options
723 *
724 * There are two ways that you can create a new SimplePie object. The first
725 * is by passing a feed URL as a parameter to the SimplePie constructor
726 * (as well as optionally setting the cache location and cache expiry). This
727 * will initialise the whole feed with all of the default settings, and you
728 * can begin accessing methods and properties immediately.
729 *
730 * The second way is to create the SimplePie object with no parameters
731 * at all. This will enable you to set configuration options. After setting
732 * them, you must initialise the feed using $feed->init(). At that point the
733 * object's methods and properties will be available to you. This format is
734 * what is used throughout this documentation.
735 *
736 * @access public
737 * @since 1.0 Preview Release
738 */
739 public function __construct()
740 {
741 if (version_compare(PHP_VERSION, '5.0', '<'))
742 {
743 trigger_error('PHP 4.x is no longer supported. Please upgrade to PHP 5.2 or newer.');
744 die();
745 }
746
747 // Other objects, instances created here so we can set options on them
748 $this->sanitize = new SimplePie_Sanitize();
749
750 if (func_num_args() > 0)
751 {
752 trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.');
753 }
754 }
755
756 /**
757 * Used for converting object to a string
758 */
759 public function __toString()
760 {
761 return md5(serialize($this->data));
762 }
763
764 /**
765 * Remove items that link back to this before destroying this object
766 */
767 public function __destruct()
768 {
769 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
770 {
771 if (!empty($this->data['items']))
772 {
773 foreach ($this->data['items'] as $item)
774 {
775 $item->__destruct();
776 }
777 unset($item, $this->data['items']);
778 }
779 if (!empty($this->data['ordered_items']))
780 {
781 foreach ($this->data['ordered_items'] as $item)
782 {
783 $item->__destruct();
784 }
785 unset($item, $this->data['ordered_items']);
786 }
787 }
788 }
789
790 /**
791 * Force the given data/URL to be treated as a feed no matter what it
792 * appears like
793 *
794 * @access public
795 * @since 1.1
796 * @param bool $enable Force the given data/URL to be treated as a feed
797 */
798 public function force_feed($enable = false)
799 {
800 $this->force_feed = (bool) $enable;
801 }
802
803 /**
804 * This is the URL of the feed you want to parse.
805 *
806 * This allows you to enter the URL of the feed you want to parse, or the
807 * website you want to try to use auto-discovery on. This takes priority
808 * over any set raw data.
809 *
810 * You can set multiple feeds to mash together by passing an array instead
811 * of a string for the $url. Remember that with each additional feed comes
812 * additional processing and resources.
813 *
814 * @access public
815 * @since 1.0 Preview Release
816 * @param mixed $url This is the URL (or array of URLs) that you want to parse.
817 * @see SimplePie::set_raw_data()
818 */
819 public function set_feed_url($url)
820 {
821 if (is_array($url))
822 {
823 $this->multifeed_url = array();
824 foreach ($url as $value)
825 {
826 $this->multifeed_url[] = SimplePie_Misc::fix_protocol($value, 1);
827 }
828 }
829 else
830 {
831 $this->feed_url = SimplePie_Misc::fix_protocol($url, 1);
832 }
833 }
834
835 /**
836 * Provides an instance of SimplePie_File to use as a feed
837 *
838 * @access public
839 * @param object &$file Instance of SimplePie_File (or subclass)
840 * @return bool True on success, false on failure
841 */
842 public function set_file(&$file)
843 {
844 if (is_a($file, 'SimplePie_File'))
845 {
846 $this->feed_url = $file->url;
847 $this->file =& $file;
848 return true;
849 }
850 return false;
851 }
852
853 /**
854 * Allows you to use a string of RSS/Atom data instead of a remote feed.
855 *
856 * If you have a feed available as a string in PHP, you can tell SimplePie
857 * to parse that data string instead of a remote feed. Any set feed URL
858 * takes precedence.
859 *
860 * @access public
861 * @since 1.0 Beta 3
862 * @param string $data RSS or Atom data as a string.
863 * @see SimplePie::set_feed_url()
864 */
865 public function set_raw_data($data)
866 {
867 $this->raw_data = $data;
868 }
869
870 /**
871 * Allows you to override the default timeout for fetching remote feeds.
872 *
873 * This allows you to change the maximum time the feed's server to respond
874 * and send the feed back.
875 *
876 * @access public
877 * @since 1.0 Beta 3
878 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
879 */
880 public function set_timeout($timeout = 10)
881 {
882 $this->timeout = (int) $timeout;
883 }
884
885 /**
886 * Forces SimplePie to use fsockopen() instead of the preferred cURL
887 * functions.
888 *
889 * @access public
890 * @since 1.0 Beta 3
891 * @param bool $enable Force fsockopen() to be used
892 */
893 public function force_fsockopen($enable = false)
894 {
895 $this->force_fsockopen = (bool) $enable;
896 }
897
898 /**
899 * Enables/disables caching in SimplePie.
900 *
901 * This option allows you to disable caching all-together in SimplePie.
902 * However, disabling the cache can lead to longer load times.
903 *
904 * @access public
905 * @since 1.0 Preview Release
906 * @param bool $enable Enable caching
907 */
908 public function enable_cache($enable = true)
909 {
910 $this->cache = (bool) $enable;
911 }
912
913 /**
914 * Set the length of time (in seconds) that the contents of a feed
915 * will be cached.
916 *
917 * @access public
918 * @param int $seconds The feed content cache duration.
919 */
920 public function set_cache_duration($seconds = 3600)
921 {
922 $this->cache_duration = (int) $seconds;
923 }
924
925 /**
926 * Set the length of time (in seconds) that the autodiscovered feed
927 * URL will be cached.
928 *
929 * @access public
930 * @param int $seconds The autodiscovered feed URL cache duration.
931 */
932 public function set_autodiscovery_cache_duration($seconds = 604800)
933 {
934 $this->autodiscovery_cache_duration = (int) $seconds;
935 }
936
937 /**
938 * Set the file system location where the cached files should be stored.
939 *
940 * @access public
941 * @param string $location The file system location.
942 */
943 public function set_cache_location($location = './cache')
944 {
945 $this->cache_location = (string) $location;
946 }
947
948 /**
949 * Determines whether feed items should be sorted into reverse chronological order.
950 *
951 * @access public
952 * @param bool $enable Sort as reverse chronological order.
953 */
954 public function enable_order_by_date($enable = true)
955 {
956 $this->order_by_date = (bool) $enable;
957 }
958
959 /**
960 * Allows you to override the character encoding reported by the feed.
961 *
962 * @access public
963 * @param string $encoding Character encoding.
964 */
965 public function set_input_encoding($encoding = false)
966 {
967 if ($encoding)
968 {
969 $this->input_encoding = (string) $encoding;
970 }
971 else
972 {
973 $this->input_encoding = false;
974 }
975 }
976
977 /**
978 * Set how much feed autodiscovery to do
979 *
980 * @access public
981 * @see SIMPLEPIE_LOCATOR_NONE
982 * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
983 * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
984 * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
985 * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
986 * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
987 * @see SIMPLEPIE_LOCATOR_ALL
988 * @param int $level Feed Autodiscovery Level (level can be a
989 * combination of the above constants, see bitwise OR operator)
990 */
991 public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
992 {
993 $this->autodiscovery = (int) $level;
994 }
995
996 /**
997 * Allows you to change which class SimplePie uses for caching.
998 * Useful when you are overloading or extending SimplePie's default classes.
999 *
1000 * @access public
1001 * @param string $class Name of custom class.
1002 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1003 */
1004 public function set_cache_class($class = 'SimplePie_Cache')
1005 {
1006 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Cache'))
1007 {
1008 $this->cache_class = $class;
1009 return true;
1010 }
1011 return false;
1012 }
1013
1014 /**
1015 * Allows you to change which class SimplePie uses for auto-discovery.
1016 * Useful when you are overloading or extending SimplePie's default classes.
1017 *
1018 * @access public
1019 * @param string $class Name of custom class.
1020 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1021 */
1022 public function set_locator_class($class = 'SimplePie_Locator')
1023 {
1024 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Locator'))
1025 {
1026 $this->locator_class = $class;
1027 return true;
1028 }
1029 return false;
1030 }
1031
1032 /**
1033 * Allows you to change which class SimplePie uses for XML parsing.
1034 * Useful when you are overloading or extending SimplePie's default classes.
1035 *
1036 * @access public
1037 * @param string $class Name of custom class.
1038 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1039 */
1040 public function set_parser_class($class = 'SimplePie_Parser')
1041 {
1042 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser'))
1043 {
1044 $this->parser_class = $class;
1045 return true;
1046 }
1047 return false;
1048 }
1049
1050 /**
1051 * Allows you to change which class SimplePie uses for remote file fetching.
1052 * Useful when you are overloading or extending SimplePie's default classes.
1053 *
1054 * @access public
1055 * @param string $class Name of custom class.
1056 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1057 */
1058 public function set_file_class($class = 'SimplePie_File')
1059 {
1060 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_File'))
1061 {
1062 $this->file_class = $class;
1063 return true;
1064 }
1065 return false;
1066 }
1067
1068 /**
1069 * Allows you to change which class SimplePie uses for data sanitization.
1070 * Useful when you are overloading or extending SimplePie's default classes.
1071 *
1072 * @access public
1073 * @param string $class Name of custom class.
1074 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1075 */
1076 public function set_sanitize_class($class = 'SimplePie_Sanitize')
1077 {
1078 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize'))
1079 {
1080 $this->sanitize = new $class();
1081 return true;
1082 }
1083 return false;
1084 }
1085
1086 /**
1087 * Allows you to change which class SimplePie uses for handling feed items.
1088 * Useful when you are overloading or extending SimplePie's default classes.
1089 *
1090 * @access public
1091 * @param string $class Name of custom class.
1092 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1093 */
1094 public function set_item_class($class = 'SimplePie_Item')
1095 {
1096 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item'))
1097 {
1098 $this->item_class = $class;
1099 return true;
1100 }
1101 return false;
1102 }
1103
1104 /**
1105 * Allows you to change which class SimplePie uses for handling author data.
1106 * Useful when you are overloading or extending SimplePie's default classes.
1107 *
1108 * @access public
1109 * @param string $class Name of custom class.
1110 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1111 */
1112 public function set_author_class($class = 'SimplePie_Author')
1113 {
1114 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author'))
1115 {
1116 $this->author_class = $class;
1117 return true;
1118 }
1119 return false;
1120 }
1121
1122 /**
1123 * Allows you to change which class SimplePie uses for handling category data.
1124 * Useful when you are overloading or extending SimplePie's default classes.
1125 *
1126 * @access public
1127 * @param string $class Name of custom class.
1128 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1129 */
1130 public function set_category_class($class = 'SimplePie_Category')
1131 {
1132 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category'))
1133 {
1134 $this->category_class = $class;
1135 return true;
1136 }
1137 return false;
1138 }
1139
1140 /**
1141 * Allows you to change which class SimplePie uses for feed enclosures.
1142 * Useful when you are overloading or extending SimplePie's default classes.
1143 *
1144 * @access public
1145 * @param string $class Name of custom class.
1146 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1147 */
1148 public function set_enclosure_class($class = 'SimplePie_Enclosure')
1149 {
1150 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure'))
1151 {
1152 $this->enclosure_class = $class;
1153 return true;
1154 }
1155 return false;
1156 }
1157
1158 /**
1159 * Allows you to change which class SimplePie uses for <media:text> captions
1160 * Useful when you are overloading or extending SimplePie's default classes.
1161 *
1162 * @access public
1163 * @param string $class Name of custom class.
1164 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1165 */
1166 public function set_caption_class($class = 'SimplePie_Caption')
1167 {
1168 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Caption'))
1169 {
1170 $this->caption_class = $class;
1171 return true;
1172 }
1173 return false;
1174 }
1175
1176 /**
1177 * Allows you to change which class SimplePie uses for <media:copyright>
1178 * Useful when you are overloading or extending SimplePie's default classes.
1179 *
1180 * @access public
1181 * @param string $class Name of custom class.
1182 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1183 */
1184 public function set_copyright_class($class = 'SimplePie_Copyright')
1185 {
1186 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Copyright'))
1187 {
1188 $this->copyright_class = $class;
1189 return true;
1190 }
1191 return false;
1192 }
1193
1194 /**
1195 * Allows you to change which class SimplePie uses for <media:credit>
1196 * Useful when you are overloading or extending SimplePie's default classes.
1197 *
1198 * @access public
1199 * @param string $class Name of custom class.
1200 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1201 */
1202 public function set_credit_class($class = 'SimplePie_Credit')
1203 {
1204 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Credit'))
1205 {
1206 $this->credit_class = $class;
1207 return true;
1208 }
1209 return false;
1210 }
1211
1212 /**
1213 * Allows you to change which class SimplePie uses for <media:rating>
1214 * Useful when you are overloading or extending SimplePie's default classes.
1215 *
1216 * @access public
1217 * @param string $class Name of custom class.
1218 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1219 */
1220 public function set_rating_class($class = 'SimplePie_Rating')
1221 {
1222 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Rating'))
1223 {
1224 $this->rating_class = $class;
1225 return true;
1226 }
1227 return false;
1228 }
1229
1230 /**
1231 * Allows you to change which class SimplePie uses for <media:restriction>
1232 * Useful when you are overloading or extending SimplePie's default classes.
1233 *
1234 * @access public
1235 * @param string $class Name of custom class.
1236 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1237 */
1238 public function set_restriction_class($class = 'SimplePie_Restriction')
1239 {
1240 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Restriction'))
1241 {
1242 $this->restriction_class = $class;
1243 return true;
1244 }
1245 return false;
1246 }
1247
1248 /**
1249 * Allows you to change which class SimplePie uses for content-type sniffing.
1250 * Useful when you are overloading or extending SimplePie's default classes.
1251 *
1252 * @access public
1253 * @param string $class Name of custom class.
1254 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1255 */
1256 public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1257 {
1258 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer'))
1259 {
1260 $this->content_type_sniffer_class = $class;
1261 return true;
1262 }
1263 return false;
1264 }
1265
1266 /**
1267 * Allows you to change which class SimplePie uses item sources.
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/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1273 */
1274 public function set_source_class($class = 'SimplePie_Source')
1275 {
1276 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source'))
1277 {
1278 $this->source_class = $class;
1279 return true;
1280 }
1281 return false;
1282 }
1283
1284 /**
1285 * Allows you to override the default user agent string.
1286 *
1287 * @access public
1288 * @param string $ua New user agent string.
1289 */
1290 public function set_useragent($ua = SIMPLEPIE_USERAGENT)
1291 {
1292 $this->useragent = (string) $ua;
1293 }
1294
1295 /**
1296 * Set callback function to create cache filename with
1297 *
1298 * @access public
1299 * @param mixed $function Callback function
1300 */
1301 public function set_cache_name_function($function = 'md5')
1302 {
1303 if (is_callable($function))
1304 {
1305 $this->cache_name_function = $function;
1306 }
1307 }
1308
1309 /**
1310 * Set options to make SP as fast as possible. Forgoes a
1311 * substantial amount of data sanitization in favor of speed.
1312 *
1313 * @access public
1314 * @param bool $set Whether to set them or not
1315 */
1316 public function set_stupidly_fast($set = false)
1317 {
1318 if ($set)
1319 {
1320 $this->enable_order_by_date(false);
1321 $this->remove_div(false);
1322 $this->strip_comments(false);
1323 $this->strip_htmltags(false);
1324 $this->strip_attributes(false);
1325 $this->set_image_handler(false);
1326 }
1327 }
1328
1329 /**
1330 * Set maximum number of feeds to check with autodiscovery
1331 *
1332 * @access public
1333 * @param int $max Maximum number of feeds to check
1334 */
1335 public function set_max_checked_feeds($max = 10)
1336 {
1337 $this->max_checked_feeds = (int) $max;
1338 }
1339
1340 public function remove_div($enable = true)
1341 {
1342 $this->sanitize->remove_div($enable);
1343 }
1344
1345 public function strip_htmltags($tags = '', $encode = null)
1346 {
1347 if ($tags === '')
1348 {
1349 $tags = $this->strip_htmltags;
1350 }
1351 $this->sanitize->strip_htmltags($tags);
1352 if ($encode !== null)
1353 {
1354 $this->sanitize->encode_instead_of_strip($tags);
1355 }
1356 }
1357
1358 public function encode_instead_of_strip($enable = true)
1359 {
1360 $this->sanitize->encode_instead_of_strip($enable);
1361 }
1362
1363 public function strip_attributes($attribs = '')
1364 {
1365 if ($attribs === '')
1366 {
1367 $attribs = $this->strip_attributes;
1368 }
1369 $this->sanitize->strip_attributes($attribs);
1370 }
1371
1372 public function set_output_encoding($encoding = 'UTF-8')
1373 {
1374 $this->sanitize->set_output_encoding($encoding);
1375 }
1376
1377 public function strip_comments($strip = false)
1378 {
1379 $this->sanitize->strip_comments($strip);
1380 }
1381
1382 /**
1383 * Set element/attribute key/value pairs of HTML attributes
1384 * containing URLs that need to be resolved relative to the feed
1385 *
1386 * @access public
1387 * @since 1.0
1388 * @param array $element_attribute Element/attribute key/value pairs
1389 */
1390 public 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'))
1391 {
1392 $this->sanitize->set_url_replacements($element_attribute);
1393 }
1394
1395 /**
1396 * Set the handler to enable the display of cached images.
1397 *
1398 * @access public
1399 * @param str $page Web-accessible path to the handler_image.php file.
1400 * @param str $qs The query string that the value should be passed to.
1401 */
1402 public function set_image_handler($page = false, $qs = 'i')
1403 {
1404 if ($page !== false)
1405 {
1406 $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1407 }
1408 else
1409 {
1410 $this->image_handler = '';
1411 }
1412 }
1413
1414 /**
1415 * Set the limit for items returned per-feed with multifeeds.
1416 *
1417 * @access public
1418 * @param integer $limit The maximum number of items to return.
1419 */
1420 public function set_item_limit($limit = 0)
1421 {
1422 $this->item_limit = (int) $limit;
1423 }
1424
1425 public function init()
1426 {
1427 // Check absolute bare minimum requirements.
1428 if ((function_exists('version_compare') && version_compare(PHP_VERSION, '5.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre'))
1429 {
1430 return false;
1431 }
1432 // 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.
1433 elseif (!extension_loaded('xmlreader'))
1434 {
1435 static $xml_is_sane = null;
1436 if ($xml_is_sane === null)
1437 {
1438 $parser_check = xml_parser_create();
1439 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1440 xml_parser_free($parser_check);
1441 $xml_is_sane = isset($values[0]['value']);
1442 }
1443 if (!$xml_is_sane)
1444 {
1445 return false;
1446 }
1447 }
1448
1449 // Pass whatever was set with config options over to the sanitizer.
1450 $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->cache_class);
1451 $this->sanitize->pass_file_data($this->file_class, $this->timeout, $this->useragent, $this->force_fsockopen);
1452
1453 if ($this->feed_url !== null || $this->raw_data !== null)
1454 {
1455 $this->error = null;
1456 $this->data = array();
1457 $this->multifeed_objects = array();
1458 $cache = false;
1459
1460 if ($this->feed_url !== null)
1461 {
1462 $parsed_feed_url = SimplePie_Misc::parse_url($this->feed_url);
1463 // Decide whether to enable caching
1464 if ($this->cache && $parsed_feed_url['scheme'] !== '')
1465 {
1466 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc');
1467 }
1468 // If it's enabled and we don't want an XML dump, use the cache
1469 if ($cache && !$this->xml_dump)
1470 {
1471 // Load the Cache
1472 $this->data = $cache->load();
1473 if (!empty($this->data))
1474 {
1475 // If the cache is for an outdated build of SimplePie
1476 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1477 {
1478 $cache->unlink();
1479 $this->data = array();
1480 }
1481 // If we've hit a collision just rerun it with caching disabled
1482 elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1483 {
1484 $cache = false;
1485 $this->data = array();
1486 }
1487 // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1488 elseif (isset($this->data['feed_url']))
1489 {
1490 // If the autodiscovery cache is still valid use it.
1491 if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1492 {
1493 // Do not need to do feed autodiscovery yet.
1494 if ($this->data['feed_url'] === $this->data['url'])
1495 {
1496 $cache->unlink();
1497 $this->data = array();
1498 }
1499 else
1500 {
1501 $this->set_feed_url($this->data['feed_url']);
1502 return $this->init();
1503 }
1504 }
1505 }
1506 // Check if the cache has been updated
1507 elseif ($cache->mtime() + $this->cache_duration < time())
1508 {
1509 // If we have last-modified and/or etag set
1510 if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1511 {
1512 $headers = array(
1513 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1514 );
1515 if (isset($this->data['headers']['last-modified']))
1516 {
1517 $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1518 }
1519 if (isset($this->data['headers']['etag']))
1520 {
1521 $headers['if-none-match'] = $this->data['headers']['etag'];
1522 }
1523
1524 $file = new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen);
1525
1526 if ($file->success)
1527 {
1528 if ($file->status_code === 304)
1529 {
1530 $cache->touch();
1531 return true;
1532 }
1533 else
1534 {
1535 $headers = $file->headers;
1536 }
1537 }
1538 else
1539 {
1540 unset($file);
1541 }
1542 }
1543 }
1544 // If the cache is still valid, just return true
1545 else
1546 {
1547 $this->raw_data = false;
1548 return true;
1549 }
1550 }
1551 // If the cache is empty, delete it
1552 else
1553 {
1554 $cache->unlink();
1555 $this->data = array();
1556 }
1557 }
1558 // 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.
1559 if (!isset($file))
1560 {
1561 if (is_a($this->file, 'SimplePie_File') && $this->file->url === $this->feed_url)
1562 {
1563 $file =& $this->file;
1564 }
1565 else
1566 {
1567 $headers = array(
1568 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1569 );
1570 $file = new $this->file_class($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen);
1571 }
1572 }
1573 // If the file connection has an error, set SimplePie::error to that and quit
1574 if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1575 {
1576 $this->error = $file->error;
1577 if (!empty($this->data))
1578 {
1579 return true;
1580 }
1581 else
1582 {
1583 return false;
1584 }
1585 }
1586
1587 if (!$this->force_feed)
1588 {
1589 // Check if the supplied URL is a feed, if it isn't, look for it.
1590 $locate = new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class);
1591
1592 if (!$locate->is_feed($file))
1593 {
1594 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1595 unset($file);
1596 if ($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds))
1597 {
1598 if ($cache)
1599 {
1600 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1601 if (!$cache->save($this))
1602 {
1603 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);
1604 }
1605 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc');
1606 }
1607 $this->feed_url = $file->url;
1608 }
1609 else
1610 {
1611 $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.";
1612 SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1613 return false;
1614 }
1615 }
1616 $locate = null;
1617 }
1618
1619 $headers = $file->headers;
1620 $data = $file->body;
1621 $sniffer = new $this->content_type_sniffer_class($file);
1622 $sniffed = $sniffer->get_type();
1623 }
1624 else
1625 {
1626 $data = $this->raw_data;
1627 }
1628
1629 // This is exposed via get_raw_data()
1630 $this->raw_data = $data;
1631
1632 // Set up array of possible encodings
1633 $encodings = array();
1634
1635 // First check to see if input has been overridden.
1636 if ($this->input_encoding !== false)
1637 {
1638 $encodings[] = $this->input_encoding;
1639 }
1640
1641 $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1642 $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1643
1644 // RFC 3023 (only applies to sniffed content)
1645 if (isset($sniffed))
1646 {
1647 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1648 {
1649 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1650 {
1651 $encodings[] = strtoupper($charset[1]);
1652 }
1653 $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
1654 $encodings[] = 'UTF-8';
1655 }
1656 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1657 {
1658 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1659 {
1660 $encodings[] = $charset[1];
1661 }
1662 $encodings[] = 'US-ASCII';
1663 }
1664 // Text MIME-type default
1665 elseif (substr($sniffed, 0, 5) === 'text/')
1666 {
1667 $encodings[] = 'US-ASCII';
1668 }
1669 }
1670
1671 // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1672 $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
1673 $encodings[] = 'UTF-8';
1674 $encodings[] = 'ISO-8859-1';
1675
1676 // There's no point in trying an encoding twice
1677 $encodings = array_unique($encodings);
1678
1679 // If we want the XML, just output that with the most likely encoding and quit
1680 if ($this->xml_dump)
1681 {
1682 header('Content-type: text/xml; charset=' . $encodings[0]);
1683 echo $data;
1684 exit;
1685 }
1686
1687 // Loop through each possible encoding, till we return something, or run out of possibilities
1688 foreach ($encodings as $encoding)
1689 {
1690 // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1691 if ($utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8'))
1692 {
1693 // Create new parser
1694 $parser = new $this->parser_class();
1695
1696 // If it's parsed fine
1697 if ($parser->parse($utf8_data, 'UTF-8'))
1698 {
1699 $this->data = $parser->get_data();
1700 if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE)
1701 {
1702 if (isset($headers))
1703 {
1704 $this->data['headers'] = $headers;
1705 }
1706 $this->data['build'] = SIMPLEPIE_BUILD;
1707
1708 // Cache the file if caching is enabled
1709 if ($cache && !$cache->save($this))
1710 {
1711 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);
1712 }
1713 return true;
1714 }
1715 else
1716 {
1717 $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1718 SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1719 return false;
1720 }
1721 }
1722 }
1723 }
1724
1725 if (isset($parser))
1726 {
1727 // We have an error, just set SimplePie_Misc::error to it and quit
1728 $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());
1729 }
1730 else
1731 {
1732 $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.';
1733 }
1734
1735 SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1736
1737 return false;
1738 }
1739 elseif (!empty($this->multifeed_url))
1740 {
1741 $i = 0;
1742 $success = 0;
1743 $this->multifeed_objects = array();
1744 foreach ($this->multifeed_url as $url)
1745 {
1746 $this->multifeed_objects[$i] = clone $this;
1747 $this->multifeed_objects[$i]->set_feed_url($url);
1748 $success |= $this->multifeed_objects[$i]->init();
1749 $i++;
1750 }
1751 return (bool) $success;
1752 }
1753 else
1754 {
1755 return false;
1756 }
1757 }
1758
1759 /**
1760 * Return the error message for the occured error
1761 *
1762 * @access public
1763 * @return string Error message
1764 */
1765 public function error()
1766 {
1767 return $this->error;
1768 }
1769
1770 /**
1771 * Return the raw XML
1772 *
1773 * This is the same as setting `$xml_dump = true;`, but returns
1774 * the data instead of printing it.
1775 *
1776 * @return string|boolean Raw XML data, false if the cache is used
1777 */
1778 public function get_raw_data()
1779 {
1780 return $this->raw_data;
1781 }
1782
1783 public function get_encoding()
1784 {
1785 return $this->sanitize->output_encoding;
1786 }
1787
1788 public function handle_content_type($mime = 'text/html')
1789 {
1790 if (!headers_sent())
1791 {
1792 $header = "Content-type: $mime;";
1793 if ($this->get_encoding())
1794 {
1795 $header .= ' charset=' . $this->get_encoding();
1796 }
1797 else
1798 {
1799 $header .= ' charset=UTF-8';
1800 }
1801 header($header);
1802 }
1803 }
1804
1805 public function get_type()
1806 {
1807 if (!isset($this->data['type']))
1808 {
1809 $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1810 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1811 {
1812 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1813 }
1814 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1815 {
1816 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1817 }
1818 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1819 {
1820 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1821 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1822 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1823 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1824 {
1825 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1826 }
1827 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1828 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1829 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1830 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1831 {
1832 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1833 }
1834 }
1835 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1836 {
1837 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1838 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1839 {
1840 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1841 {
1842 case '0.91':
1843 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1844 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1845 {
1846 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1847 {
1848 case '0':
1849 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1850 break;
1851
1852 case '24':
1853 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1854 break;
1855 }
1856 }
1857 break;
1858
1859 case '0.92':
1860 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1861 break;
1862
1863 case '0.93':
1864 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1865 break;
1866
1867 case '0.94':
1868 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1869 break;
1870
1871 case '2.0':
1872 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1873 break;
1874 }
1875 }
1876 }
1877 else
1878 {
1879 $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1880 }
1881 }
1882 return $this->data['type'];
1883 }
1884
1885 /**
1886 * @todo If we have a perm redirect we should return the new URL
1887 * @todo When we make the above change, let's support <itunes:new-feed-url> as well
1888 * @todo Also, |atom:link|@rel=self
1889 */
1890 public function subscribe_url()
1891 {
1892 if ($this->feed_url !== null)
1893 {
1894 return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
1895 }
1896 else
1897 {
1898 return null;
1899 }
1900 }
1901
1902 public function get_feed_tags($namespace, $tag)
1903 {
1904 $type = $this->get_type();
1905 if ($type & SIMPLEPIE_TYPE_ATOM_10)
1906 {
1907 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1908 {
1909 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1910 }
1911 }
1912 if ($type & SIMPLEPIE_TYPE_ATOM_03)
1913 {
1914 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1915 {
1916 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1917 }
1918 }
1919 if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1920 {
1921 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
1922 {
1923 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
1924 }
1925 }
1926 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1927 {
1928 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
1929 {
1930 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
1931 }
1932 }
1933 return null;
1934 }
1935
1936 public function get_channel_tags($namespace, $tag)
1937 {
1938 $type = $this->get_type();
1939 if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
1940 {
1941 if ($return = $this->get_feed_tags($namespace, $tag))
1942 {
1943 return $return;
1944 }
1945 }
1946 if ($type & SIMPLEPIE_TYPE_RSS_10)
1947 {
1948 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
1949 {
1950 if (isset($channel[0]['child'][$namespace][$tag]))
1951 {
1952 return $channel[0]['child'][$namespace][$tag];
1953 }
1954 }
1955 }
1956 if ($type & SIMPLEPIE_TYPE_RSS_090)
1957 {
1958 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
1959 {
1960 if (isset($channel[0]['child'][$namespace][$tag]))
1961 {
1962 return $channel[0]['child'][$namespace][$tag];
1963 }
1964 }
1965 }
1966 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1967 {
1968 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
1969 {
1970 if (isset($channel[0]['child'][$namespace][$tag]))
1971 {
1972 return $channel[0]['child'][$namespace][$tag];
1973 }
1974 }
1975 }
1976 return null;
1977 }
1978
1979 public function get_image_tags($namespace, $tag)
1980 {
1981 $type = $this->get_type();
1982 if ($type & SIMPLEPIE_TYPE_RSS_10)
1983 {
1984 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1985 {
1986 if (isset($image[0]['child'][$namespace][$tag]))
1987 {
1988 return $image[0]['child'][$namespace][$tag];
1989 }
1990 }
1991 }
1992 if ($type & SIMPLEPIE_TYPE_RSS_090)
1993 {
1994 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1995 {
1996 if (isset($image[0]['child'][$namespace][$tag]))
1997 {
1998 return $image[0]['child'][$namespace][$tag];
1999 }
2000 }
2001 }
2002 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2003 {
2004 if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
2005 {
2006 if (isset($image[0]['child'][$namespace][$tag]))
2007 {
2008 return $image[0]['child'][$namespace][$tag];
2009 }
2010 }
2011 }
2012 return null;
2013 }
2014
2015 public function get_base($element = array())
2016 {
2017 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
2018 {
2019 return $element['xml_base'];
2020 }
2021 elseif ($this->get_link() !== null)
2022 {
2023 return $this->get_link();
2024 }
2025 else
2026 {
2027 return $this->subscribe_url();
2028 }
2029 }
2030
2031 public function sanitize($data, $type, $base = '')
2032 {
2033 return $this->sanitize->sanitize($data, $type, $base);
2034 }
2035
2036 public function get_title()
2037 {
2038 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
2039 {
2040 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2041 }
2042 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
2043 {
2044 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2045 }
2046 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2047 {
2048 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2049 }
2050 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2051 {
2052 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2053 }
2054 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2055 {
2056 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2057 }
2058 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2059 {
2060 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2061 }
2062 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2063 {
2064 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2065 }
2066 else
2067 {
2068 return null;
2069 }
2070 }
2071
2072 public function get_category($key = 0)
2073 {
2074 $categories = $this->get_categories();
2075 if (isset($categories[$key]))
2076 {
2077 return $categories[$key];
2078 }
2079 else
2080 {
2081 return null;
2082 }
2083 }
2084
2085 public function get_categories()
2086 {
2087 $categories = array();
2088
2089 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2090 {
2091 $term = null;
2092 $scheme = null;
2093 $label = null;
2094 if (isset($category['attribs']['']['term']))
2095 {
2096 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2097 }
2098 if (isset($category['attribs']['']['scheme']))
2099 {
2100 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2101 }
2102 if (isset($category['attribs']['']['label']))
2103 {
2104 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2105 }
2106 $categories[] = new $this->category_class($term, $scheme, $label);
2107 }
2108 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2109 {
2110 // This is really the label, but keep this as the term also for BC.
2111 // Label will also work on retrieving because that falls back to term.
2112 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2113 if (isset($category['attribs']['']['domain']))
2114 {
2115 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2116 }
2117 else
2118 {
2119 $scheme = null;
2120 }
2121 $categories[] = new $this->category_class($term, $scheme, null);
2122 }
2123 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2124 {
2125 $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2126 }
2127 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2128 {
2129 $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2130 }
2131
2132 if (!empty($categories))
2133 {
2134 return SimplePie_Misc::array_unique($categories);
2135 }
2136 else
2137 {
2138 return null;
2139 }
2140 }
2141
2142 public function get_author($key = 0)
2143 {
2144 $authors = $this->get_authors();
2145 if (isset($authors[$key]))
2146 {
2147 return $authors[$key];
2148 }
2149 else
2150 {
2151 return null;
2152 }
2153 }
2154
2155 public function get_authors()
2156 {
2157 $authors = array();
2158 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2159 {
2160 $name = null;
2161 $uri = null;
2162 $email = null;
2163 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2164 {
2165 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2166 }
2167 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2168 {
2169 $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]));
2170 }
2171 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2172 {
2173 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2174 }
2175 if ($name !== null || $email !== null || $uri !== null)
2176 {
2177 $authors[] = new $this->author_class($name, $uri, $email);
2178 }
2179 }
2180 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2181 {
2182 $name = null;
2183 $url = null;
2184 $email = null;
2185 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2186 {
2187 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2188 }
2189 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2190 {
2191 $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]));
2192 }
2193 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2194 {
2195 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2196 }
2197 if ($name !== null || $email !== null || $url !== null)
2198 {
2199 $authors[] = new $this->author_class($name, $url, $email);
2200 }
2201 }
2202 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2203 {
2204 $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2205 }
2206 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2207 {
2208 $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2209 }
2210 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2211 {
2212 $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2213 }
2214
2215 if (!empty($authors))
2216 {
2217 return SimplePie_Misc::array_unique($authors);
2218 }
2219 else
2220 {
2221 return null;
2222 }
2223 }
2224
2225 public function get_contributor($key = 0)
2226 {
2227 $contributors = $this->get_contributors();
2228 if (isset($contributors[$key]))
2229 {
2230 return $contributors[$key];
2231 }
2232 else
2233 {
2234 return null;
2235 }
2236 }
2237
2238 public function get_contributors()
2239 {
2240 $contributors = array();
2241 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2242 {
2243 $name = null;
2244 $uri = null;
2245 $email = null;
2246 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2247 {
2248 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2249 }
2250 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2251 {
2252 $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]));
2253 }
2254 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2255 {
2256 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2257 }
2258 if ($name !== null || $email !== null || $uri !== null)
2259 {
2260 $contributors[] = new $this->author_class($name, $uri, $email);
2261 }
2262 }
2263 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2264 {
2265 $name = null;
2266 $url = null;
2267 $email = null;
2268 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2269 {
2270 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2271 }
2272 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2273 {
2274 $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]));
2275 }
2276 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2277 {
2278 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2279 }
2280 if ($name !== null || $email !== null || $url !== null)
2281 {
2282 $contributors[] = new $this->author_class($name, $url, $email);
2283 }
2284 }
2285
2286 if (!empty($contributors))
2287 {
2288 return SimplePie_Misc::array_unique($contributors);
2289 }
2290 else
2291 {
2292 return null;
2293 }
2294 }
2295
2296 public function get_link($key = 0, $rel = 'alternate')
2297 {
2298 $links = $this->get_links($rel);
2299 if (isset($links[$key]))
2300 {
2301 return $links[$key];
2302 }
2303 else
2304 {
2305 return null;
2306 }
2307 }
2308
2309 /**
2310 * Added for parity between the parent-level and the item/entry-level.
2311 */
2312 public function get_permalink()
2313 {
2314 return $this->get_link(0);
2315 }
2316
2317 public function get_links($rel = 'alternate')
2318 {
2319 if (!isset($this->data['links']))
2320 {
2321 $this->data['links'] = array();
2322 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2323 {
2324 foreach ($links as $link)
2325 {
2326 if (isset($link['attribs']['']['href']))
2327 {
2328 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2329 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2330 }
2331 }
2332 }
2333 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2334 {
2335 foreach ($links as $link)
2336 {
2337 if (isset($link['attribs']['']['href']))
2338 {
2339 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2340 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2341
2342 }
2343 }
2344 }
2345 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2346 {
2347 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2348 }
2349 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2350 {
2351 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2352 }
2353 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2354 {
2355 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2356 }
2357
2358 $keys = array_keys($this->data['links']);
2359 foreach ($keys as $key)
2360 {
2361 if (SimplePie_Misc::is_isegment_nz_nc($key))
2362 {
2363 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2364 {
2365 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2366 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2367 }
2368 else
2369 {
2370 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2371 }
2372 }
2373 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2374 {
2375 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2376 }
2377 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2378 }
2379 }
2380
2381 if (isset($this->data['links'][$rel]))
2382 {
2383 return $this->data['links'][$rel];
2384 }
2385 else
2386 {
2387 return null;
2388 }
2389 }
2390
2391 public function get_all_discovered_feeds()
2392 {
2393 return $this->all_discovered_feeds;
2394 }
2395
2396 public function get_description()
2397 {
2398 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2399 {
2400 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2401 }
2402 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2403 {
2404 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2405 }
2406 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2407 {
2408 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2409 }
2410 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2411 {
2412 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2413 }
2414 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2415 {
2416 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2417 }
2418 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2419 {
2420 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2421 }
2422 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2423 {
2424 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2425 }
2426 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2427 {
2428 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2429 }
2430 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2431 {
2432 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2433 }
2434 else
2435 {
2436 return null;
2437 }
2438 }
2439
2440 public function get_copyright()
2441 {
2442 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2443 {
2444 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2445 }
2446 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2447 {
2448 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2449 }
2450 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2451 {
2452 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2453 }
2454 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2455 {
2456 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2457 }
2458 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2459 {
2460 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2461 }
2462 else
2463 {
2464 return null;
2465 }
2466 }
2467
2468 public function get_language()
2469 {
2470 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2471 {
2472 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2473 }
2474 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2475 {
2476 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2477 }
2478 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2479 {
2480 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2481 }
2482 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2483 {
2484 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2485 }
2486 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2487 {
2488 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2489 }
2490 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2491 {
2492 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2493 }
2494 elseif (isset($this->data['headers']['content-language']))
2495 {
2496 return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2497 }
2498 else
2499 {
2500 return null;
2501 }
2502 }
2503
2504 public function get_latitude()
2505 {
2506
2507 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2508 {
2509 return (float) $return[0]['data'];
2510 }
2511 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))
2512 {
2513 return (float) $match[1];
2514 }
2515 else
2516 {
2517 return null;
2518 }
2519 }
2520
2521 public function get_longitude()
2522 {
2523 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2524 {
2525 return (float) $return[0]['data'];
2526 }
2527 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2528 {
2529 return (float) $return[0]['data'];
2530 }
2531 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))
2532 {
2533 return (float) $match[2];
2534 }
2535 else
2536 {
2537 return null;
2538 }
2539 }
2540
2541 public function get_image_title()
2542 {
2543 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2544 {
2545 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2546 }
2547 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2548 {
2549 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2550 }
2551 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2552 {
2553 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2554 }
2555 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2556 {
2557 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2558 }
2559 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2560 {
2561 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2562 }
2563 else
2564 {
2565 return null;
2566 }
2567 }
2568
2569 public function get_image_url()
2570 {
2571 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2572 {
2573 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2574 }
2575 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2576 {
2577 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2578 }
2579 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2580 {
2581 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2582 }
2583 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2584 {
2585 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2586 }
2587 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2588 {
2589 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2590 }
2591 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2592 {
2593 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2594 }
2595 else
2596 {
2597 return null;
2598 }
2599 }
2600
2601 public function get_image_link()
2602 {
2603 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2604 {
2605 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2606 }
2607 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2608 {
2609 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2610 }
2611 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2612 {
2613 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2614 }
2615 else
2616 {
2617 return null;
2618 }
2619 }
2620
2621 public function get_image_width()
2622 {
2623 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2624 {
2625 return round($return[0]['data']);
2626 }
2627 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2628 {
2629 return 88.0;
2630 }
2631 else
2632 {
2633 return null;
2634 }
2635 }
2636
2637 public function get_image_height()
2638 {
2639 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2640 {
2641 return round($return[0]['data']);
2642 }
2643 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2644 {
2645 return 31.0;
2646 }
2647 else
2648 {
2649 return null;
2650 }
2651 }
2652
2653 public function get_item_quantity($max = 0)
2654 {
2655 $max = (int) $max;
2656 $qty = count($this->get_items());
2657 if ($max === 0)
2658 {
2659 return $qty;
2660 }
2661 else
2662 {
2663 return ($qty > $max) ? $max : $qty;
2664 }
2665 }
2666
2667 public function get_item($key = 0)
2668 {
2669 $items = $this->get_items();
2670 if (isset($items[$key]))
2671 {
2672 return $items[$key];
2673 }
2674 else
2675 {
2676 return null;
2677 }
2678 }
2679
2680 public function get_items($start = 0, $end = 0)
2681 {
2682 if (!isset($this->data['items']))
2683 {
2684 if (!empty($this->multifeed_objects))
2685 {
2686 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
2687 }
2688 else
2689 {
2690 $this->data['items'] = array();
2691 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
2692 {
2693 $keys = array_keys($items);
2694 foreach ($keys as $key)
2695 {
2696 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2697 }
2698 }
2699 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
2700 {
2701 $keys = array_keys($items);
2702 foreach ($keys as $key)
2703 {
2704 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2705 }
2706 }
2707 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
2708 {
2709 $keys = array_keys($items);
2710 foreach ($keys as $key)
2711 {
2712 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2713 }
2714 }
2715 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2716 {
2717 $keys = array_keys($items);
2718 foreach ($keys as $key)
2719 {
2720 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2721 }
2722 }
2723 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
2724 {
2725 $keys = array_keys($items);
2726 foreach ($keys as $key)
2727 {
2728 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2729 }
2730 }
2731 }
2732 }
2733
2734 if (!empty($this->data['items']))
2735 {
2736 // If we want to order it by date, check if all items have a date, and then sort it
2737 if ($this->order_by_date && empty($this->multifeed_objects))
2738 {
2739 if (!isset($this->data['ordered_items']))
2740 {
2741 $do_sort = true;
2742 foreach ($this->data['items'] as $item)
2743 {
2744 if (!$item->get_date('U'))
2745 {
2746 $do_sort = false;
2747 break;
2748 }
2749 }
2750 $item = null;
2751 $this->data['ordered_items'] = $this->data['items'];
2752 if ($do_sort)
2753 {
2754 usort($this->data['ordered_items'], array(&$this, 'sort_items'));
2755 }
2756 }
2757 $items = $this->data['ordered_items'];
2758 }
2759 else
2760 {
2761 $items = $this->data['items'];
2762 }
2763
2764 // Slice the data as desired
2765 if ($end === 0)
2766 {
2767 return array_slice($items, $start);
2768 }
2769 else
2770 {
2771 return array_slice($items, $start, $end);
2772 }
2773 }
2774 else
2775 {
2776 return array();
2777 }
2778 }
2779
2780 /**
2781 * @static
2782 */
2783 public function sort_items($a, $b)
2784 {
2785 return $a->get_date('U') <= $b->get_date('U');
2786 }
2787
2788 /**
2789 * @static
2790 */
2791 public function merge_items($urls, $start = 0, $end = 0, $limit = 0)
2792 {
2793 if (is_array($urls) && sizeof($urls) > 0)
2794 {
2795 $items = array();
2796 foreach ($urls as $arg)
2797 {
2798 if (is_a($arg, 'SimplePie'))
2799 {
2800 $items = array_merge($items, $arg->get_items(0, $limit));
2801 }
2802 else
2803 {
2804 trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
2805 }
2806 }
2807
2808 $do_sort = true;
2809 foreach ($items as $item)
2810 {
2811 if (!$item->get_date('U'))
2812 {
2813 $do_sort = false;
2814 break;
2815 }
2816 }
2817 $item = null;
2818 if ($do_sort)
2819 {
2820 usort($items, array('SimplePie', 'sort_items'));
2821 }
2822
2823 if ($end === 0)
2824 {
2825 return array_slice($items, $start);
2826 }
2827 else
2828 {
2829 return array_slice($items, $start, $end);
2830 }
2831 }
2832 else
2833 {
2834 trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
2835 return array();
2836 }
2837 }
2838 }