Projet

Général

Profil

Paste
Télécharger (86,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / libraries / simplepie-1.3.1 / library / SimplePie.php @ 4b706e38

1
<?php
2
/**
3
 * SimplePie
4
 *
5
 * A PHP-Based RSS and Atom Feed Framework.
6
 * Takes the hard work out of managing a complete RSS/Atom solution.
7
 *
8
 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without modification, are
12
 * permitted provided that the following conditions are met:
13
 *
14
 *         * Redistributions of source code must retain the above copyright notice, this list of
15
 *           conditions and the following disclaimer.
16
 *
17
 *         * Redistributions in binary form must reproduce the above copyright notice, this list
18
 *           of conditions and the following disclaimer in the documentation and/or other materials
19
 *           provided with the distribution.
20
 *
21
 *         * Neither the name of the SimplePie Team nor the names of its contributors may be used
22
 *           to endorse or promote products derived from this software without specific prior
23
 *           written permission.
24
 *
25
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28
 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
 * POSSIBILITY OF SUCH DAMAGE.
34
 *
35
 * @package SimplePie
36
 * @version 1.3.1
37
 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38
 * @author Ryan Parman
39
 * @author Geoffrey Sneddon
40
 * @author Ryan McCue
41
 * @link http://simplepie.org/ SimplePie
42
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43
 */
44

    
45
/**
46
 * SimplePie Name
47
 */
48
define('SIMPLEPIE_NAME', 'SimplePie');
49

    
50
/**
51
 * SimplePie Version
52
 */
53
define('SIMPLEPIE_VERSION', '1.3.1');
54

    
55
/**
56
 * SimplePie Build
57
 * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
58
 */
59
define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::get_build()));
60

    
61
/**
62
 * SimplePie Website URL
63
 */
64
define('SIMPLEPIE_URL', 'http://simplepie.org');
65

    
66
/**
67
 * SimplePie Useragent
68
 * @see SimplePie::set_useragent()
69
 */
70
define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
71

    
72
/**
73
 * SimplePie Linkback
74
 */
75
define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
76

    
77
/**
78
 * No Autodiscovery
79
 * @see SimplePie::set_autodiscovery_level()
80
 */
81
define('SIMPLEPIE_LOCATOR_NONE', 0);
82

    
83
/**
84
 * Feed Link Element Autodiscovery
85
 * @see SimplePie::set_autodiscovery_level()
86
 */
87
define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
88

    
89
/**
90
 * Local Feed Extension Autodiscovery
91
 * @see SimplePie::set_autodiscovery_level()
92
 */
93
define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
94

    
95
/**
96
 * Local Feed Body Autodiscovery
97
 * @see SimplePie::set_autodiscovery_level()
98
 */
99
define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
100

    
101
/**
102
 * Remote Feed Extension Autodiscovery
103
 * @see SimplePie::set_autodiscovery_level()
104
 */
105
define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
106

    
107
/**
108
 * Remote Feed Body Autodiscovery
109
 * @see SimplePie::set_autodiscovery_level()
110
 */
111
define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
112

    
113
/**
114
 * All Feed Autodiscovery
115
 * @see SimplePie::set_autodiscovery_level()
116
 */
117
define('SIMPLEPIE_LOCATOR_ALL', 31);
118

    
119
/**
120
 * No known feed type
121
 */
122
define('SIMPLEPIE_TYPE_NONE', 0);
123

    
124
/**
125
 * RSS 0.90
126
 */
127
define('SIMPLEPIE_TYPE_RSS_090', 1);
128

    
129
/**
130
 * RSS 0.91 (Netscape)
131
 */
132
define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
133

    
134
/**
135
 * RSS 0.91 (Userland)
136
 */
137
define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
138

    
139
/**
140
 * RSS 0.91 (both Netscape and Userland)
141
 */
142
define('SIMPLEPIE_TYPE_RSS_091', 6);
143

    
144
/**
145
 * RSS 0.92
146
 */
147
define('SIMPLEPIE_TYPE_RSS_092', 8);
148

    
149
/**
150
 * RSS 0.93
151
 */
152
define('SIMPLEPIE_TYPE_RSS_093', 16);
153

    
154
/**
155
 * RSS 0.94
156
 */
157
define('SIMPLEPIE_TYPE_RSS_094', 32);
158

    
159
/**
160
 * RSS 1.0
161
 */
162
define('SIMPLEPIE_TYPE_RSS_10', 64);
163

    
164
/**
165
 * RSS 2.0
166
 */
167
define('SIMPLEPIE_TYPE_RSS_20', 128);
168

    
169
/**
170
 * RDF-based RSS
171
 */
172
define('SIMPLEPIE_TYPE_RSS_RDF', 65);
173

    
174
/**
175
 * Non-RDF-based RSS (truly intended as syndication format)
176
 */
177
define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
178

    
179
/**
180
 * All RSS
181
 */
182
define('SIMPLEPIE_TYPE_RSS_ALL', 255);
183

    
184
/**
185
 * Atom 0.3
186
 */
187
define('SIMPLEPIE_TYPE_ATOM_03', 256);
188

    
189
/**
190
 * Atom 1.0
191
 */
192
define('SIMPLEPIE_TYPE_ATOM_10', 512);
193

    
194
/**
195
 * All Atom
196
 */
197
define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
198

    
199
/**
200
 * All feed types
201
 */
202
define('SIMPLEPIE_TYPE_ALL', 1023);
203

    
204
/**
205
 * No construct
206
 */
207
define('SIMPLEPIE_CONSTRUCT_NONE', 0);
208

    
209
/**
210
 * Text construct
211
 */
212
define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
213

    
214
/**
215
 * HTML construct
216
 */
217
define('SIMPLEPIE_CONSTRUCT_HTML', 2);
218

    
219
/**
220
 * XHTML construct
221
 */
222
define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
223

    
224
/**
225
 * base64-encoded construct
226
 */
227
define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
228

    
229
/**
230
 * IRI construct
231
 */
232
define('SIMPLEPIE_CONSTRUCT_IRI', 16);
233

    
234
/**
235
 * A construct that might be HTML
236
 */
237
define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
238

    
239
/**
240
 * All constructs
241
 */
242
define('SIMPLEPIE_CONSTRUCT_ALL', 63);
243

    
244
/**
245
 * Don't change case
246
 */
247
define('SIMPLEPIE_SAME_CASE', 1);
248

    
249
/**
250
 * Change to lowercase
251
 */
252
define('SIMPLEPIE_LOWERCASE', 2);
253

    
254
/**
255
 * Change to uppercase
256
 */
257
define('SIMPLEPIE_UPPERCASE', 4);
258

    
259
/**
260
 * PCRE for HTML attributes
261
 */
262
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]*');
263

    
264
/**
265
 * PCRE for XML attributes
266
 */
267
define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
268

    
269
/**
270
 * XML Namespace
271
 */
272
define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
273

    
274
/**
275
 * Atom 1.0 Namespace
276
 */
277
define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
278

    
279
/**
280
 * Atom 0.3 Namespace
281
 */
282
define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
283

    
284
/**
285
 * RDF Namespace
286
 */
287
define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
288

    
289
/**
290
 * RSS 0.90 Namespace
291
 */
292
define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
293

    
294
/**
295
 * RSS 1.0 Namespace
296
 */
297
define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
298

    
299
/**
300
 * RSS 1.0 Content Module Namespace
301
 */
302
define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
303

    
304
/**
305
 * RSS 2.0 Namespace
306
 * (Stupid, I know, but I'm certain it will confuse people less with support.)
307
 */
308
define('SIMPLEPIE_NAMESPACE_RSS_20', '');
309

    
310
/**
311
 * DC 1.0 Namespace
312
 */
313
define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
314

    
315
/**
316
 * DC 1.1 Namespace
317
 */
318
define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
319

    
320
/**
321
 * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
322
 */
323
define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
324

    
325
/**
326
 * GeoRSS Namespace
327
 */
328
define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
329

    
330
/**
331
 * Media RSS Namespace
332
 */
333
define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
334

    
335
/**
336
 * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
337
 */
338
define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
339

    
340
/**
341
 * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
342
 */
343
define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
344

    
345
/**
346
 * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
347
 */
348
define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
349

    
350
/**
351
 * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
352
 */
353
define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
354

    
355
/**
356
 * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
357
 */
358
define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
359

    
360
/**
361
 * iTunes RSS Namespace
362
 */
363
define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
364

    
365
/**
366
 * XHTML Namespace
367
 */
368
define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
369

    
370
/**
371
 * IANA Link Relations Registry
372
 */
373
define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
374

    
375
/**
376
 * No file source
377
 */
378
define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
379

    
380
/**
381
 * Remote file source
382
 */
383
define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
384

    
385
/**
386
 * Local file source
387
 */
388
define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
389

    
390
/**
391
 * fsockopen() file source
392
 */
393
define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
394

    
395
/**
396
 * cURL file source
397
 */
398
define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
399

    
400
/**
401
 * file_get_contents() file source
402
 */
403
define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
404

    
405

    
406

    
407
/**
408
 * SimplePie
409
 *
410
 * @package SimplePie
411
 * @subpackage API
412
 */
413
class SimplePie
414
{
415
        /**
416
         * @var array Raw data
417
         * @access private
418
         */
419
        public $data = array();
420

    
421
        /**
422
         * @var mixed Error string
423
         * @access private
424
         */
425
        public $error;
426

    
427
        /**
428
         * @var object Instance of SimplePie_Sanitize (or other class)
429
         * @see SimplePie::set_sanitize_class()
430
         * @access private
431
         */
432
        public $sanitize;
433

    
434
        /**
435
         * @var string SimplePie Useragent
436
         * @see SimplePie::set_useragent()
437
         * @access private
438
         */
439
        public $useragent = SIMPLEPIE_USERAGENT;
440

    
441
        /**
442
         * @var string Feed URL
443
         * @see SimplePie::set_feed_url()
444
         * @access private
445
         */
446
        public $feed_url;
447

    
448
        /**
449
         * @var object Instance of SimplePie_File to use as a feed
450
         * @see SimplePie::set_file()
451
         * @access private
452
         */
453
        public $file;
454

    
455
        /**
456
         * @var string Raw feed data
457
         * @see SimplePie::set_raw_data()
458
         * @access private
459
         */
460
        public $raw_data;
461

    
462
        /**
463
         * @var int Timeout for fetching remote files
464
         * @see SimplePie::set_timeout()
465
         * @access private
466
         */
467
        public $timeout = 10;
468

    
469
        /**
470
         * @var bool Forces fsockopen() to be used for remote files instead
471
         * of cURL, even if a new enough version is installed
472
         * @see SimplePie::force_fsockopen()
473
         * @access private
474
         */
475
        public $force_fsockopen = false;
476

    
477
        /**
478
         * @var bool Force the given data/URL to be treated as a feed no matter what
479
         * it appears like
480
         * @see SimplePie::force_feed()
481
         * @access private
482
         */
483
        public $force_feed = false;
484

    
485
        /**
486
         * @var bool Enable/Disable Caching
487
         * @see SimplePie::enable_cache()
488
         * @access private
489
         */
490
        public $cache = true;
491

    
492
        /**
493
         * @var int Cache duration (in seconds)
494
         * @see SimplePie::set_cache_duration()
495
         * @access private
496
         */
497
        public $cache_duration = 3600;
498

    
499
        /**
500
         * @var int Auto-discovery cache duration (in seconds)
501
         * @see SimplePie::set_autodiscovery_cache_duration()
502
         * @access private
503
         */
504
        public $autodiscovery_cache_duration = 604800; // 7 Days.
505

    
506
        /**
507
         * @var string Cache location (relative to executing script)
508
         * @see SimplePie::set_cache_location()
509
         * @access private
510
         */
511
        public $cache_location = './cache';
512

    
513
        /**
514
         * @var string Function that creates the cache filename
515
         * @see SimplePie::set_cache_name_function()
516
         * @access private
517
         */
518
        public $cache_name_function = 'md5';
519

    
520
        /**
521
         * @var bool Reorder feed by date descending
522
         * @see SimplePie::enable_order_by_date()
523
         * @access private
524
         */
525
        public $order_by_date = true;
526

    
527
        /**
528
         * @var mixed Force input encoding to be set to the follow value
529
         * (false, or anything type-cast to false, disables this feature)
530
         * @see SimplePie::set_input_encoding()
531
         * @access private
532
         */
533
        public $input_encoding = false;
534

    
535
        /**
536
         * @var int Feed Autodiscovery Level
537
         * @see SimplePie::set_autodiscovery_level()
538
         * @access private
539
         */
540
        public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
541

    
542
        /**
543
         * Class registry object
544
         *
545
         * @var SimplePie_Registry
546
         */
547
        public $registry;
548

    
549
        /**
550
         * @var int Maximum number of feeds to check with autodiscovery
551
         * @see SimplePie::set_max_checked_feeds()
552
         * @access private
553
         */
554
        public $max_checked_feeds = 10;
555

    
556
        /**
557
         * @var array All the feeds found during the autodiscovery process
558
         * @see SimplePie::get_all_discovered_feeds()
559
         * @access private
560
         */
561
        public $all_discovered_feeds = array();
562

    
563
        /**
564
         * @var string Web-accessible path to the handler_image.php file.
565
         * @see SimplePie::set_image_handler()
566
         * @access private
567
         */
568
        public $image_handler = '';
569

    
570
        /**
571
         * @var array Stores the URLs when multiple feeds are being initialized.
572
         * @see SimplePie::set_feed_url()
573
         * @access private
574
         */
575
        public $multifeed_url = array();
576

    
577
        /**
578
         * @var array Stores SimplePie objects when multiple feeds initialized.
579
         * @access private
580
         */
581
        public $multifeed_objects = array();
582

    
583
        /**
584
         * @var array Stores the get_object_vars() array for use with multifeeds.
585
         * @see SimplePie::set_feed_url()
586
         * @access private
587
         */
588
        public $config_settings = null;
589

    
590
        /**
591
         * @var integer Stores the number of items to return per-feed with multifeeds.
592
         * @see SimplePie::set_item_limit()
593
         * @access private
594
         */
595
        public $item_limit = 0;
596

    
597
        /**
598
         * @var array Stores the default attributes to be stripped by strip_attributes().
599
         * @see SimplePie::strip_attributes()
600
         * @access private
601
         */
602
        public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
603

    
604
        /**
605
         * @var array Stores the default tags to be stripped by strip_htmltags().
606
         * @see SimplePie::strip_htmltags()
607
         * @access private
608
         */
609
        public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
610

    
611
        /**
612
         * The SimplePie class contains feed level data and options
613
         *
614
         * To use SimplePie, create the SimplePie object with no parameters. You can
615
         * then set configuration options using the provided methods. After setting
616
         * them, you must initialise the feed using $feed->init(). At that point the
617
         * object's methods and properties will be available to you.
618
         *
619
         * Previously, it was possible to pass in the feed URL along with cache
620
         * options directly into the constructor. This has been removed as of 1.3 as
621
         * it caused a lot of confusion.
622
         *
623
         * @since 1.0 Preview Release
624
         */
625
        public function __construct()
626
        {
627
                if (version_compare(PHP_VERSION, '5.2', '<'))
628
                {
629
                        trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
630
                        die();
631
                }
632

    
633
                // Other objects, instances created here so we can set options on them
634
                $this->sanitize = new SimplePie_Sanitize();
635
                $this->registry = new SimplePie_Registry();
636

    
637
                if (func_num_args() > 0)
638
                {
639
                        $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
640
                        trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
641

    
642
                        $args = func_get_args();
643
                        switch (count($args)) {
644
                                case 3:
645
                                        $this->set_cache_duration($args[2]);
646
                                case 2:
647
                                        $this->set_cache_location($args[1]);
648
                                case 1:
649
                                        $this->set_feed_url($args[0]);
650
                                        $this->init();
651
                        }
652
                }
653
        }
654

    
655
        /**
656
         * Used for converting object to a string
657
         */
658
        public function __toString()
659
        {
660
                return md5(serialize($this->data));
661
        }
662

    
663
        /**
664
         * Remove items that link back to this before destroying this object
665
         */
666
        public function __destruct()
667
        {
668
                if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
669
                {
670
                        if (!empty($this->data['items']))
671
                        {
672
                                foreach ($this->data['items'] as $item)
673
                                {
674
                                        $item->__destruct();
675
                                }
676
                                unset($item, $this->data['items']);
677
                        }
678
                        if (!empty($this->data['ordered_items']))
679
                        {
680
                                foreach ($this->data['ordered_items'] as $item)
681
                                {
682
                                        $item->__destruct();
683
                                }
684
                                unset($item, $this->data['ordered_items']);
685
                        }
686
                }
687
        }
688

    
689
        /**
690
         * Force the given data/URL to be treated as a feed
691
         *
692
         * This tells SimplePie to ignore the content-type provided by the server.
693
         * Be careful when using this option, as it will also disable autodiscovery.
694
         *
695
         * @since 1.1
696
         * @param bool $enable Force the given data/URL to be treated as a feed
697
         */
698
        public function force_feed($enable = false)
699
        {
700
                $this->force_feed = (bool) $enable;
701
        }
702

    
703
        /**
704
         * Set the URL of the feed you want to parse
705
         *
706
         * This allows you to enter the URL of the feed you want to parse, or the
707
         * website you want to try to use auto-discovery on. This takes priority
708
         * over any set raw data.
709
         *
710
         * You can set multiple feeds to mash together by passing an array instead
711
         * of a string for the $url. Remember that with each additional feed comes
712
         * additional processing and resources.
713
         *
714
         * @since 1.0 Preview Release
715
         * @see set_raw_data()
716
         * @param string|array $url This is the URL (or array of URLs) that you want to parse.
717
         */
718
        public function set_feed_url($url)
719
        {
720
                $this->multifeed_url = array();
721
                if (is_array($url))
722
                {
723
                        foreach ($url as $value)
724
                        {
725
                                $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
726
                        }
727
                }
728
                else
729
                {
730
                        $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
731
                }
732
        }
733

    
734
        /**
735
         * Set an instance of {@see SimplePie_File} to use as a feed
736
         *
737
         * @param SimplePie_File &$file
738
         * @return bool True on success, false on failure
739
         */
740
        public function set_file(&$file)
741
        {
742
                if ($file instanceof SimplePie_File)
743
                {
744
                        $this->feed_url = $file->url;
745
                        $this->file =& $file;
746
                        return true;
747
                }
748
                return false;
749
        }
750

    
751
        /**
752
         * Set the raw XML data to parse
753
         *
754
         * Allows you to use a string of RSS/Atom data instead of a remote feed.
755
         *
756
         * If you have a feed available as a string in PHP, you can tell SimplePie
757
         * to parse that data string instead of a remote feed. Any set feed URL
758
         * takes precedence.
759
         *
760
         * @since 1.0 Beta 3
761
         * @param string $data RSS or Atom data as a string.
762
         * @see set_feed_url()
763
         */
764
        public function set_raw_data($data)
765
        {
766
                $this->raw_data = $data;
767
        }
768

    
769
        /**
770
         * Set the the default timeout for fetching remote feeds
771
         *
772
         * This allows you to change the maximum time the feed's server to respond
773
         * and send the feed back.
774
         *
775
         * @since 1.0 Beta 3
776
         * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
777
         */
778
        public function set_timeout($timeout = 10)
779
        {
780
                $this->timeout = (int) $timeout;
781
        }
782

    
783
        /**
784
         * Force SimplePie to use fsockopen() instead of cURL
785
         *
786
         * @since 1.0 Beta 3
787
         * @param bool $enable Force fsockopen() to be used
788
         */
789
        public function force_fsockopen($enable = false)
790
        {
791
                $this->force_fsockopen = (bool) $enable;
792
        }
793

    
794
        /**
795
         * Enable/disable caching in SimplePie.
796
         *
797
         * This option allows you to disable caching all-together in SimplePie.
798
         * However, disabling the cache can lead to longer load times.
799
         *
800
         * @since 1.0 Preview Release
801
         * @param bool $enable Enable caching
802
         */
803
        public function enable_cache($enable = true)
804
        {
805
                $this->cache = (bool) $enable;
806
        }
807

    
808
        /**
809
         * Set the length of time (in seconds) that the contents of a feed will be
810
         * cached
811
         *
812
         * @param int $seconds The feed content cache duration
813
         */
814
        public function set_cache_duration($seconds = 3600)
815
        {
816
                $this->cache_duration = (int) $seconds;
817
        }
818

    
819
        /**
820
         * Set the length of time (in seconds) that the autodiscovered feed URL will
821
         * be cached
822
         *
823
         * @param int $seconds The autodiscovered feed URL cache duration.
824
         */
825
        public function set_autodiscovery_cache_duration($seconds = 604800)
826
        {
827
                $this->autodiscovery_cache_duration = (int) $seconds;
828
        }
829

    
830
        /**
831
         * Set the file system location where the cached files should be stored
832
         *
833
         * @param string $location The file system location.
834
         */
835
        public function set_cache_location($location = './cache')
836
        {
837
                $this->cache_location = (string) $location;
838
        }
839

    
840
        /**
841
         * Set whether feed items should be sorted into reverse chronological order
842
         *
843
         * @param bool $enable Sort as reverse chronological order.
844
         */
845
        public function enable_order_by_date($enable = true)
846
        {
847
                $this->order_by_date = (bool) $enable;
848
        }
849

    
850
        /**
851
         * Set the character encoding used to parse the feed
852
         *
853
         * This overrides the encoding reported by the feed, however it will fall
854
         * back to the normal encoding detection if the override fails
855
         *
856
         * @param string $encoding Character encoding
857
         */
858
        public function set_input_encoding($encoding = false)
859
        {
860
                if ($encoding)
861
                {
862
                        $this->input_encoding = (string) $encoding;
863
                }
864
                else
865
                {
866
                        $this->input_encoding = false;
867
                }
868
        }
869

    
870
        /**
871
         * Set how much feed autodiscovery to do
872
         *
873
         * @see SIMPLEPIE_LOCATOR_NONE
874
         * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
875
         * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
876
         * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
877
         * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
878
         * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
879
         * @see SIMPLEPIE_LOCATOR_ALL
880
         * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
881
         */
882
        public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
883
        {
884
                $this->autodiscovery = (int) $level;
885
        }
886

    
887
        /**
888
         * Get the class registry
889
         *
890
         * Use this to override SimplePie's default classes
891
         * @see SimplePie_Registry
892
         * @return SimplePie_Registry
893
         */
894
        public function &get_registry()
895
        {
896
                return $this->registry;
897
        }
898

    
899
        /**#@+
900
         * Useful when you are overloading or extending SimplePie's default classes.
901
         *
902
         * @deprecated Use {@see get_registry()} instead
903
         * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
904
         * @param string $class Name of custom class
905
         * @return boolean True on success, false otherwise
906
         */
907
        /**
908
         * Set which class SimplePie uses for caching
909
         */
910
        public function set_cache_class($class = 'SimplePie_Cache')
911
        {
912
                return $this->registry->register('Cache', $class, true);
913
        }
914

    
915
        /**
916
         * Set which class SimplePie uses for auto-discovery
917
         */
918
        public function set_locator_class($class = 'SimplePie_Locator')
919
        {
920
                return $this->registry->register('Locator', $class, true);
921
        }
922

    
923
        /**
924
         * Set which class SimplePie uses for XML parsing
925
         */
926
        public function set_parser_class($class = 'SimplePie_Parser')
927
        {
928
                return $this->registry->register('Parser', $class, true);
929
        }
930

    
931
        /**
932
         * Set which class SimplePie uses for remote file fetching
933
         */
934
        public function set_file_class($class = 'SimplePie_File')
935
        {
936
                return $this->registry->register('File', $class, true);
937
        }
938

    
939
        /**
940
         * Set which class SimplePie uses for data sanitization
941
         */
942
        public function set_sanitize_class($class = 'SimplePie_Sanitize')
943
        {
944
                return $this->registry->register('Sanitize', $class, true);
945
        }
946

    
947
        /**
948
         * Set which class SimplePie uses for handling feed items
949
         */
950
        public function set_item_class($class = 'SimplePie_Item')
951
        {
952
                return $this->registry->register('Item', $class, true);
953
        }
954

    
955
        /**
956
         * Set which class SimplePie uses for handling author data
957
         */
958
        public function set_author_class($class = 'SimplePie_Author')
959
        {
960
                return $this->registry->register('Author', $class, true);
961
        }
962

    
963
        /**
964
         * Set which class SimplePie uses for handling category data
965
         */
966
        public function set_category_class($class = 'SimplePie_Category')
967
        {
968
                return $this->registry->register('Category', $class, true);
969
        }
970

    
971
        /**
972
         * Set which class SimplePie uses for feed enclosures
973
         */
974
        public function set_enclosure_class($class = 'SimplePie_Enclosure')
975
        {
976
                return $this->registry->register('Enclosure', $class, true);
977
        }
978

    
979
        /**
980
         * Set which class SimplePie uses for `<media:text>` captions
981
         */
982
        public function set_caption_class($class = 'SimplePie_Caption')
983
        {
984
                return $this->registry->register('Caption', $class, true);
985
        }
986

    
987
        /**
988
         * Set which class SimplePie uses for `<media:copyright>`
989
         */
990
        public function set_copyright_class($class = 'SimplePie_Copyright')
991
        {
992
                return $this->registry->register('Copyright', $class, true);
993
        }
994

    
995
        /**
996
         * Set which class SimplePie uses for `<media:credit>`
997
         */
998
        public function set_credit_class($class = 'SimplePie_Credit')
999
        {
1000
                return $this->registry->register('Credit', $class, true);
1001
        }
1002

    
1003
        /**
1004
         * Set which class SimplePie uses for `<media:rating>`
1005
         */
1006
        public function set_rating_class($class = 'SimplePie_Rating')
1007
        {
1008
                return $this->registry->register('Rating', $class, true);
1009
        }
1010

    
1011
        /**
1012
         * Set which class SimplePie uses for `<media:restriction>`
1013
         */
1014
        public function set_restriction_class($class = 'SimplePie_Restriction')
1015
        {
1016
                return $this->registry->register('Restriction', $class, true);
1017
        }
1018

    
1019
        /**
1020
         * Set which class SimplePie uses for content-type sniffing
1021
         */
1022
        public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1023
        {
1024
                return $this->registry->register('Content_Type_Sniffer', $class, true);
1025
        }
1026

    
1027
        /**
1028
         * Set which class SimplePie uses item sources
1029
         */
1030
        public function set_source_class($class = 'SimplePie_Source')
1031
        {
1032
                return $this->registry->register('Source', $class, true);
1033
        }
1034
        /**#@-*/
1035

    
1036
        /**
1037
         * Set the user agent string
1038
         *
1039
         * @param string $ua New user agent string.
1040
         */
1041
        public function set_useragent($ua = SIMPLEPIE_USERAGENT)
1042
        {
1043
                $this->useragent = (string) $ua;
1044
        }
1045

    
1046
        /**
1047
         * Set callback function to create cache filename with
1048
         *
1049
         * @param mixed $function Callback function
1050
         */
1051
        public function set_cache_name_function($function = 'md5')
1052
        {
1053
                if (is_callable($function))
1054
                {
1055
                        $this->cache_name_function = $function;
1056
                }
1057
        }
1058

    
1059
        /**
1060
         * Set options to make SP as fast as possible
1061
         *
1062
         * Forgoes a substantial amount of data sanitization in favor of speed. This
1063
         * turns SimplePie into a dumb parser of feeds.
1064
         *
1065
         * @param bool $set Whether to set them or not
1066
         */
1067
        public function set_stupidly_fast($set = false)
1068
        {
1069
                if ($set)
1070
                {
1071
                        $this->enable_order_by_date(false);
1072
                        $this->remove_div(false);
1073
                        $this->strip_comments(false);
1074
                        $this->strip_htmltags(false);
1075
                        $this->strip_attributes(false);
1076
                        $this->set_image_handler(false);
1077
                }
1078
        }
1079

    
1080
        /**
1081
         * Set maximum number of feeds to check with autodiscovery
1082
         *
1083
         * @param int $max Maximum number of feeds to check
1084
         */
1085
        public function set_max_checked_feeds($max = 10)
1086
        {
1087
                $this->max_checked_feeds = (int) $max;
1088
        }
1089

    
1090
        public function remove_div($enable = true)
1091
        {
1092
                $this->sanitize->remove_div($enable);
1093
        }
1094

    
1095
        public function strip_htmltags($tags = '', $encode = null)
1096
        {
1097
                if ($tags === '')
1098
                {
1099
                        $tags = $this->strip_htmltags;
1100
                }
1101
                $this->sanitize->strip_htmltags($tags);
1102
                if ($encode !== null)
1103
                {
1104
                        $this->sanitize->encode_instead_of_strip($tags);
1105
                }
1106
        }
1107

    
1108
        public function encode_instead_of_strip($enable = true)
1109
        {
1110
                $this->sanitize->encode_instead_of_strip($enable);
1111
        }
1112

    
1113
        public function strip_attributes($attribs = '')
1114
        {
1115
                if ($attribs === '')
1116
                {
1117
                        $attribs = $this->strip_attributes;
1118
                }
1119
                $this->sanitize->strip_attributes($attribs);
1120
        }
1121

    
1122
        /**
1123
         * Set the output encoding
1124
         *
1125
         * Allows you to override SimplePie's output to match that of your webpage.
1126
         * This is useful for times when your webpages are not being served as
1127
         * UTF-8.  This setting will be obeyed by {@see handle_content_type()}, and
1128
         * is similar to {@see set_input_encoding()}.
1129
         *
1130
         * It should be noted, however, that not all character encodings can support
1131
         * all characters.  If your page is being served as ISO-8859-1 and you try
1132
         * to display a Japanese feed, you'll likely see garbled characters.
1133
         * Because of this, it is highly recommended to ensure that your webpages
1134
         * are served as UTF-8.
1135
         *
1136
         * The number of supported character encodings depends on whether your web
1137
         * host supports {@link http://php.net/mbstring mbstring},
1138
         * {@link http://php.net/iconv iconv}, or both. See
1139
         * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
1140
         * more information.
1141
         *
1142
         * @param string $encoding
1143
         */
1144
        public function set_output_encoding($encoding = 'UTF-8')
1145
        {
1146
                $this->sanitize->set_output_encoding($encoding);
1147
        }
1148

    
1149
        public function strip_comments($strip = false)
1150
        {
1151
                $this->sanitize->strip_comments($strip);
1152
        }
1153

    
1154
        /**
1155
         * Set element/attribute key/value pairs of HTML attributes
1156
         * containing URLs that need to be resolved relative to the feed
1157
         *
1158
         * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
1159
         * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
1160
         * |q|@cite
1161
         *
1162
         * @since 1.0
1163
         * @param array|null $element_attribute Element/attribute key/value pairs, null for default
1164
         */
1165
        public function set_url_replacements($element_attribute = null)
1166
        {
1167
                $this->sanitize->set_url_replacements($element_attribute);
1168
        }
1169

    
1170
        /**
1171
         * Set the handler to enable the display of cached images.
1172
         *
1173
         * @param str $page Web-accessible path to the handler_image.php file.
1174
         * @param str $qs The query string that the value should be passed to.
1175
         */
1176
        public function set_image_handler($page = false, $qs = 'i')
1177
        {
1178
                if ($page !== false)
1179
                {
1180
                        $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1181
                }
1182
                else
1183
                {
1184
                        $this->image_handler = '';
1185
                }
1186
        }
1187

    
1188
        /**
1189
         * Set the limit for items returned per-feed with multifeeds
1190
         *
1191
         * @param integer $limit The maximum number of items to return.
1192
         */
1193
        public function set_item_limit($limit = 0)
1194
        {
1195
                $this->item_limit = (int) $limit;
1196
        }
1197

    
1198
        /**
1199
         * Initialize the feed object
1200
         *
1201
         * This is what makes everything happen.  Period.  This is where all of the
1202
         * configuration options get processed, feeds are fetched, cached, and
1203
         * parsed, and all of that other good stuff.
1204
         *
1205
         * @return boolean True if successful, false otherwise
1206
         */
1207
        public function init()
1208
        {
1209
                // Check absolute bare minimum requirements.
1210
                if (!extension_loaded('xml') || !extension_loaded('pcre'))
1211
                {
1212
                        return false;
1213
                }
1214
                // 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.
1215
                elseif (!extension_loaded('xmlreader'))
1216
                {
1217
                        static $xml_is_sane = null;
1218
                        if ($xml_is_sane === null)
1219
                        {
1220
                                $parser_check = xml_parser_create();
1221
                                xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1222
                                xml_parser_free($parser_check);
1223
                                $xml_is_sane = isset($values[0]['value']);
1224
                        }
1225
                        if (!$xml_is_sane)
1226
                        {
1227
                                return false;
1228
                        }
1229
                }
1230

    
1231
                if (method_exists($this->sanitize, 'set_registry'))
1232
                {
1233
                        $this->sanitize->set_registry($this->registry);
1234
                }
1235

    
1236
                // Pass whatever was set with config options over to the sanitizer.
1237
                // Pass the classes in for legacy support; new classes should use the registry instead
1238
                $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
1239
                $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
1240

    
1241
                if (!empty($this->multifeed_url))
1242
                {
1243
                        $i = 0;
1244
                        $success = 0;
1245
                        $this->multifeed_objects = array();
1246
                        $this->error = array();
1247
                        foreach ($this->multifeed_url as $url)
1248
                        {
1249
                                $this->multifeed_objects[$i] = clone $this;
1250
                                $this->multifeed_objects[$i]->set_feed_url($url);
1251
                                $single_success = $this->multifeed_objects[$i]->init();
1252
                                $success |= $single_success;
1253
                                if (!$single_success)
1254
                                {
1255
                                        $this->error[$i] = $this->multifeed_objects[$i]->error();
1256
                                }
1257
                                $i++;
1258
                        }
1259
                        return (bool) $success;
1260
                }
1261
                elseif ($this->feed_url === null && $this->raw_data === null)
1262
                {
1263
                        return false;
1264
                }
1265

    
1266
                $this->error = null;
1267
                $this->data = array();
1268
                $this->multifeed_objects = array();
1269
                $cache = false;
1270

    
1271
                if ($this->feed_url !== null)
1272
                {
1273
                        $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
1274

    
1275
                        // Decide whether to enable caching
1276
                        if ($this->cache && $parsed_feed_url['scheme'] !== '')
1277
                        {
1278
                                $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
1279
                        }
1280

    
1281
                        // Fetch the data via SimplePie_File into $this->raw_data
1282
                        if (($fetched = $this->fetch_data($cache)) === true)
1283
                        {
1284
                                return true;
1285
                        }
1286
                        elseif ($fetched === false) {
1287
                                return false;
1288
                        }
1289

    
1290
                        list($headers, $sniffed) = $fetched;
1291
                }
1292

    
1293
                // Set up array of possible encodings
1294
                $encodings = array();
1295

    
1296
                // First check to see if input has been overridden.
1297
                if ($this->input_encoding !== false)
1298
                {
1299
                        $encodings[] = $this->input_encoding;
1300
                }
1301

    
1302
                $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1303
                $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1304

    
1305
                // RFC 3023 (only applies to sniffed content)
1306
                if (isset($sniffed))
1307
                {
1308
                        if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1309
                        {
1310
                                if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1311
                                {
1312
                                        $encodings[] = strtoupper($charset[1]);
1313
                                }
1314
                                $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1315
                                $encodings[] = 'UTF-8';
1316
                        }
1317
                        elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1318
                        {
1319
                                if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1320
                                {
1321
                                        $encodings[] = $charset[1];
1322
                                }
1323
                                $encodings[] = 'US-ASCII';
1324
                        }
1325
                        // Text MIME-type default
1326
                        elseif (substr($sniffed, 0, 5) === 'text/')
1327
                        {
1328
                                $encodings[] = 'US-ASCII';
1329
                        }
1330
                }
1331

    
1332
                // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1333
                $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1334
                $encodings[] = 'UTF-8';
1335
                $encodings[] = 'ISO-8859-1';
1336

    
1337
                // There's no point in trying an encoding twice
1338
                $encodings = array_unique($encodings);
1339

    
1340
                // Loop through each possible encoding, till we return something, or run out of possibilities
1341
                foreach ($encodings as $encoding)
1342
                {
1343
                        // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1344
                        if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
1345
                        {
1346
                                // Create new parser
1347
                                $parser = $this->registry->create('Parser');
1348

    
1349
                                // If it's parsed fine
1350
                                if ($parser->parse($utf8_data, 'UTF-8'))
1351
                                {
1352
                                        $this->data = $parser->get_data();
1353
                                        if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
1354
                                        {
1355
                                                $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1356
                                                $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1357
                                                return false;
1358
                                        }
1359

    
1360
                                        if (isset($headers))
1361
                                        {
1362
                                                $this->data['headers'] = $headers;
1363
                                        }
1364
                                        $this->data['build'] = SIMPLEPIE_BUILD;
1365

    
1366
                                        // Cache the file if caching is enabled
1367
                                        if ($cache && !$cache->save($this))
1368
                                        {
1369
                                                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);
1370
                                        }
1371
                                        return true;
1372
                                }
1373
                        }
1374
                }
1375

    
1376
                if (isset($parser))
1377
                {
1378
                        // We have an error, just set SimplePie_Misc::error to it and quit
1379
                        $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());
1380
                }
1381
                else
1382
                {
1383
                        $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.';
1384
                }
1385

    
1386
                $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1387

    
1388
                return false;
1389
        }
1390

    
1391
        /**
1392
         * Fetch the data via SimplePie_File
1393
         *
1394
         * If the data is already cached, attempt to fetch it from there instead
1395
         * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
1396
         * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
1397
         */
1398
        protected function fetch_data(&$cache)
1399
        {
1400
                // If it's enabled, use the cache
1401
                if ($cache)
1402
                {
1403
                        // Load the Cache
1404
                        $this->data = $cache->load();
1405
                        if (!empty($this->data))
1406
                        {
1407
                                // If the cache is for an outdated build of SimplePie
1408
                                if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1409
                                {
1410
                                        $cache->unlink();
1411
                                        $this->data = array();
1412
                                }
1413
                                // If we've hit a collision just rerun it with caching disabled
1414
                                elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1415
                                {
1416
                                        $cache = false;
1417
                                        $this->data = array();
1418
                                }
1419
                                // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1420
                                elseif (isset($this->data['feed_url']))
1421
                                {
1422
                                        // If the autodiscovery cache is still valid use it.
1423
                                        if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1424
                                        {
1425
                                                // Do not need to do feed autodiscovery yet.
1426
                                                if ($this->data['feed_url'] !== $this->data['url'])
1427
                                                {
1428
                                                        $this->set_feed_url($this->data['feed_url']);
1429
                                                        return $this->init();
1430
                                                }
1431

    
1432
                                                $cache->unlink();
1433
                                                $this->data = array();
1434
                                        }
1435
                                }
1436
                                // Check if the cache has been updated
1437
                                elseif ($cache->mtime() + $this->cache_duration < time())
1438
                                {
1439
                                        // If we have last-modified and/or etag set
1440
                                        if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1441
                                        {
1442
                                                $headers = array(
1443
                                                        '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',
1444
                                                );
1445
                                                if (isset($this->data['headers']['last-modified']))
1446
                                                {
1447
                                                        $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1448
                                                }
1449
                                                if (isset($this->data['headers']['etag']))
1450
                                                {
1451
                                                        $headers['if-none-match'] = $this->data['headers']['etag'];
1452
                                                }
1453

    
1454
                                                $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
1455

    
1456
                                                if ($file->success)
1457
                                                {
1458
                                                        if ($file->status_code === 304)
1459
                                                        {
1460
                                                                $cache->touch();
1461
                                                                return true;
1462
                                                        }
1463
                                                }
1464
                                                else
1465
                                                {
1466
                                                        unset($file);
1467
                                                }
1468
                                        }
1469
                                }
1470
                                // If the cache is still valid, just return true
1471
                                else
1472
                                {
1473
                                        $this->raw_data = false;
1474
                                        return true;
1475
                                }
1476
                        }
1477
                        // If the cache is empty, delete it
1478
                        else
1479
                        {
1480
                                $cache->unlink();
1481
                                $this->data = array();
1482
                        }
1483
                }
1484
                // 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.
1485
                if (!isset($file))
1486
                {
1487
                        if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
1488
                        {
1489
                                $file =& $this->file;
1490
                        }
1491
                        else
1492
                        {
1493
                                $headers = array(
1494
                                        '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',
1495
                                );
1496
                                $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
1497
                        }
1498
                }
1499
                // If the file connection has an error, set SimplePie::error to that and quit
1500
                if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1501
                {
1502
                        $this->error = $file->error;
1503
                        return !empty($this->data);
1504
                }
1505

    
1506
                if (!$this->force_feed)
1507
                {
1508
                        // Check if the supplied URL is a feed, if it isn't, look for it.
1509
                        $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
1510

    
1511
                        if (!$locate->is_feed($file))
1512
                        {
1513
                                // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1514
                                unset($file);
1515
                                try
1516
                                {
1517
                                        if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
1518
                                        {
1519
                                                $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.";
1520
                                                $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1521
                                                return false;
1522
                                        }
1523
                                }
1524
                                catch (SimplePie_Exception $e)
1525
                                {
1526
                                        // This is usually because DOMDocument doesn't exist
1527
                                        $this->error = $e->getMessage();
1528
                                        $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
1529
                                        return false;
1530
                                }
1531
                                if ($cache)
1532
                                {
1533
                                        $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1534
                                        if (!$cache->save($this))
1535
                                        {
1536
                                                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);
1537
                                        }
1538
                                        $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
1539
                                }
1540
                                $this->feed_url = $file->url;
1541
                        }
1542
                        $locate = null;
1543
                }
1544

    
1545
                $this->raw_data = $file->body;
1546

    
1547
                $headers = $file->headers;
1548
                $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
1549
                $sniffed = $sniffer->get_type();
1550

    
1551
                return array($headers, $sniffed);
1552
        }
1553

    
1554
        /**
1555
         * Get the error message for the occured error
1556
         *
1557
         * @return string|array Error message, or array of messages for multifeeds
1558
         */
1559
        public function error()
1560
        {
1561
                return $this->error;
1562
        }
1563

    
1564
        /**
1565
         * Get the raw XML
1566
         *
1567
         * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
1568
         * the data instead of printing it.
1569
         *
1570
         * @return string|boolean Raw XML data, false if the cache is used
1571
         */
1572
        public function get_raw_data()
1573
        {
1574
                return $this->raw_data;
1575
        }
1576

    
1577
        /**
1578
         * Get the character encoding used for output
1579
         *
1580
         * @since Preview Release
1581
         * @return string
1582
         */
1583
        public function get_encoding()
1584
        {
1585
                return $this->sanitize->output_encoding;
1586
        }
1587

    
1588
        /**
1589
         * Send the content-type header with correct encoding
1590
         *
1591
         * This method ensures that the SimplePie-enabled page is being served with
1592
         * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
1593
         * and character encoding HTTP headers (character encoding determined by the
1594
         * {@see set_output_encoding} config option).
1595
         *
1596
         * This won't work properly if any content or whitespace has already been
1597
         * sent to the browser, because it relies on PHP's
1598
         * {@link http://php.net/header header()} function, and these are the
1599
         * circumstances under which the function works.
1600
         *
1601
         * Because it's setting these settings for the entire page (as is the nature
1602
         * of HTTP headers), this should only be used once per page (again, at the
1603
         * top).
1604
         *
1605
         * @param string $mime MIME type to serve the page as
1606
         */
1607
        public function handle_content_type($mime = 'text/html')
1608
        {
1609
                if (!headers_sent())
1610
                {
1611
                        $header = "Content-type: $mime;";
1612
                        if ($this->get_encoding())
1613
                        {
1614
                                $header .= ' charset=' . $this->get_encoding();
1615
                        }
1616
                        else
1617
                        {
1618
                                $header .= ' charset=UTF-8';
1619
                        }
1620
                        header($header);
1621
                }
1622
        }
1623

    
1624
        /**
1625
         * Get the type of the feed
1626
         *
1627
         * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
1628
         * using {@link http://php.net/language.operators.bitwise bitwise operators}
1629
         *
1630
         * @since 0.8 (usage changed to using constants in 1.0)
1631
         * @see SIMPLEPIE_TYPE_NONE Unknown.
1632
         * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
1633
         * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
1634
         * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
1635
         * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
1636
         * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
1637
         * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
1638
         * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
1639
         * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
1640
         * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
1641
         * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
1642
         * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
1643
         * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
1644
         * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
1645
         * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
1646
         * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
1647
         * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
1648
         * @return int SIMPLEPIE_TYPE_* constant
1649
         */
1650
        public function get_type()
1651
        {
1652
                if (!isset($this->data['type']))
1653
                {
1654
                        $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1655
                        if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1656
                        {
1657
                                $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1658
                        }
1659
                        elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1660
                        {
1661
                                $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1662
                        }
1663
                        elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1664
                        {
1665
                                if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1666
                                || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1667
                                || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1668
                                || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1669
                                {
1670
                                        $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1671
                                }
1672
                                if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1673
                                || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1674
                                || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1675
                                || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1676
                                {
1677
                                        $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1678
                                }
1679
                        }
1680
                        elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1681
                        {
1682
                                $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1683
                                if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1684
                                {
1685
                                        switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1686
                                        {
1687
                                                case '0.91':
1688
                                                        $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1689
                                                        if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1690
                                                        {
1691
                                                                switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1692
                                                                {
1693
                                                                        case '0':
1694
                                                                                $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1695
                                                                                break;
1696

    
1697
                                                                        case '24':
1698
                                                                                $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1699
                                                                                break;
1700
                                                                }
1701
                                                        }
1702
                                                        break;
1703

    
1704
                                                case '0.92':
1705
                                                        $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1706
                                                        break;
1707

    
1708
                                                case '0.93':
1709
                                                        $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1710
                                                        break;
1711

    
1712
                                                case '0.94':
1713
                                                        $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1714
                                                        break;
1715

    
1716
                                                case '2.0':
1717
                                                        $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1718
                                                        break;
1719
                                        }
1720
                                }
1721
                        }
1722
                        else
1723
                        {
1724
                                $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1725
                        }
1726
                }
1727
                return $this->data['type'];
1728
        }
1729

    
1730
        /**
1731
         * Get the URL for the feed
1732
         *
1733
         * May or may not be different from the URL passed to {@see set_feed_url()},
1734
         * depending on whether auto-discovery was used.
1735
         *
1736
         * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
1737
         * @todo If we have a perm redirect we should return the new URL
1738
         * @todo When we make the above change, let's support <itunes:new-feed-url> as well
1739
         * @todo Also, |atom:link|@rel=self
1740
         * @return string|null
1741
         */
1742
        public function subscribe_url()
1743
        {
1744
                if ($this->feed_url !== null)
1745
                {
1746
                        return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
1747
                }
1748
                else
1749
                {
1750
                        return null;
1751
                }
1752
        }
1753

    
1754
        /**
1755
         * Get data for an feed-level element
1756
         *
1757
         * This method allows you to get access to ANY element/attribute that is a
1758
         * sub-element of the opening feed tag.
1759
         *
1760
         * The return value is an indexed array of elements matching the given
1761
         * namespace and tag name. Each element has `attribs`, `data` and `child`
1762
         * subkeys. For `attribs` and `child`, these contain namespace subkeys.
1763
         * `attribs` then has one level of associative name => value data (where
1764
         * `value` is a string) after the namespace. `child` has tag-indexed keys
1765
         * after the namespace, each member of which is an indexed array matching
1766
         * this same format.
1767
         *
1768
         * For example:
1769
         * <pre>
1770
         * // This is probably a bad example because we already support
1771
         * // <media:content> natively, but it shows you how to parse through
1772
         * // the nodes.
1773
         * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
1774
         * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
1775
         * $file = $content[0]['attribs']['']['url'];
1776
         * echo $file;
1777
         * </pre>
1778
         *
1779
         * @since 1.0
1780
         * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1781
         * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1782
         * @param string $tag Tag name
1783
         * @return array
1784
         */
1785
        public function get_feed_tags($namespace, $tag)
1786
        {
1787
                $type = $this->get_type();
1788
                if ($type & SIMPLEPIE_TYPE_ATOM_10)
1789
                {
1790
                        if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1791
                        {
1792
                                return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1793
                        }
1794
                }
1795
                if ($type & SIMPLEPIE_TYPE_ATOM_03)
1796
                {
1797
                        if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1798
                        {
1799
                                return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1800
                        }
1801
                }
1802
                if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1803
                {
1804
                        if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
1805
                        {
1806
                                return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
1807
                        }
1808
                }
1809
                if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1810
                {
1811
                        if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
1812
                        {
1813
                                return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
1814
                        }
1815
                }
1816
                return null;
1817
        }
1818

    
1819
        /**
1820
         * Get data for an channel-level element
1821
         *
1822
         * This method allows you to get access to ANY element/attribute in the
1823
         * channel/header section of the feed.
1824
         *
1825
         * See {@see SimplePie::get_feed_tags()} for a description of the return value
1826
         *
1827
         * @since 1.0
1828
         * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1829
         * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1830
         * @param string $tag Tag name
1831
         * @return array
1832
         */
1833
        public function get_channel_tags($namespace, $tag)
1834
        {
1835
                $type = $this->get_type();
1836
                if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
1837
                {
1838
                        if ($return = $this->get_feed_tags($namespace, $tag))
1839
                        {
1840
                                return $return;
1841
                        }
1842
                }
1843
                if ($type & SIMPLEPIE_TYPE_RSS_10)
1844
                {
1845
                        if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
1846
                        {
1847
                                if (isset($channel[0]['child'][$namespace][$tag]))
1848
                                {
1849
                                        return $channel[0]['child'][$namespace][$tag];
1850
                                }
1851
                        }
1852
                }
1853
                if ($type & SIMPLEPIE_TYPE_RSS_090)
1854
                {
1855
                        if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
1856
                        {
1857
                                if (isset($channel[0]['child'][$namespace][$tag]))
1858
                                {
1859
                                        return $channel[0]['child'][$namespace][$tag];
1860
                                }
1861
                        }
1862
                }
1863
                if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1864
                {
1865
                        if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
1866
                        {
1867
                                if (isset($channel[0]['child'][$namespace][$tag]))
1868
                                {
1869
                                        return $channel[0]['child'][$namespace][$tag];
1870
                                }
1871
                        }
1872
                }
1873
                return null;
1874
        }
1875

    
1876
        /**
1877
         * Get data for an channel-level element
1878
         *
1879
         * This method allows you to get access to ANY element/attribute in the
1880
         * image/logo section of the feed.
1881
         *
1882
         * See {@see SimplePie::get_feed_tags()} for a description of the return value
1883
         *
1884
         * @since 1.0
1885
         * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1886
         * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1887
         * @param string $tag Tag name
1888
         * @return array
1889
         */
1890
        public function get_image_tags($namespace, $tag)
1891
        {
1892
                $type = $this->get_type();
1893
                if ($type & SIMPLEPIE_TYPE_RSS_10)
1894
                {
1895
                        if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1896
                        {
1897
                                if (isset($image[0]['child'][$namespace][$tag]))
1898
                                {
1899
                                        return $image[0]['child'][$namespace][$tag];
1900
                                }
1901
                        }
1902
                }
1903
                if ($type & SIMPLEPIE_TYPE_RSS_090)
1904
                {
1905
                        if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1906
                        {
1907
                                if (isset($image[0]['child'][$namespace][$tag]))
1908
                                {
1909
                                        return $image[0]['child'][$namespace][$tag];
1910
                                }
1911
                        }
1912
                }
1913
                if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1914
                {
1915
                        if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
1916
                        {
1917
                                if (isset($image[0]['child'][$namespace][$tag]))
1918
                                {
1919
                                        return $image[0]['child'][$namespace][$tag];
1920
                                }
1921
                        }
1922
                }
1923
                return null;
1924
        }
1925

    
1926
        /**
1927
         * Get the base URL value from the feed
1928
         *
1929
         * Uses `<xml:base>` if available, otherwise uses the first link in the
1930
         * feed, or failing that, the URL of the feed itself.
1931
         *
1932
         * @see get_link
1933
         * @see subscribe_url
1934
         *
1935
         * @param array $element
1936
         * @return string
1937
         */
1938
        public function get_base($element = array())
1939
        {
1940
                if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
1941
                {
1942
                        return $element['xml_base'];
1943
                }
1944
                elseif ($this->get_link() !== null)
1945
                {
1946
                        return $this->get_link();
1947
                }
1948
                else
1949
                {
1950
                        return $this->subscribe_url();
1951
                }
1952
        }
1953

    
1954
        /**
1955
         * Sanitize feed data
1956
         *
1957
         * @access private
1958
         * @see SimplePie_Sanitize::sanitize()
1959
         * @param string $data Data to sanitize
1960
         * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
1961
         * @param string $base Base URL to resolve URLs against
1962
         * @return string Sanitized data
1963
         */
1964
        public function sanitize($data, $type, $base = '')
1965
        {
1966
                return $this->sanitize->sanitize($data, $type, $base);
1967
        }
1968

    
1969
        /**
1970
         * Get the title of the feed
1971
         *
1972
         * Uses `<atom:title>`, `<title>` or `<dc:title>`
1973
         *
1974
         * @since 1.0 (previously called `get_feed_title` since 0.8)
1975
         * @return string|null
1976
         */
1977
        public function get_title()
1978
        {
1979
                if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
1980
                {
1981
                        return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1982
                }
1983
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
1984
                {
1985
                        return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1986
                }
1987
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1988
                {
1989
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1990
                }
1991
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1992
                {
1993
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1994
                }
1995
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
1996
                {
1997
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1998
                }
1999
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2000
                {
2001
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2002
                }
2003
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2004
                {
2005
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2006
                }
2007
                else
2008
                {
2009
                        return null;
2010
                }
2011
        }
2012

    
2013
        /**
2014
         * Get a category for the feed
2015
         *
2016
         * @since Unknown
2017
         * @param int $key The category that you want to return.  Remember that arrays begin with 0, not 1
2018
         * @return SimplePie_Category|null
2019
         */
2020
        public function get_category($key = 0)
2021
        {
2022
                $categories = $this->get_categories();
2023
                if (isset($categories[$key]))
2024
                {
2025
                        return $categories[$key];
2026
                }
2027
                else
2028
                {
2029
                        return null;
2030
                }
2031
        }
2032

    
2033
        /**
2034
         * Get all categories for the feed
2035
         *
2036
         * Uses `<atom:category>`, `<category>` or `<dc:subject>`
2037
         *
2038
         * @since Unknown
2039
         * @return array|null List of {@see SimplePie_Category} objects
2040
         */
2041
        public function get_categories()
2042
        {
2043
                $categories = array();
2044

    
2045
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2046
                {
2047
                        $term = null;
2048
                        $scheme = null;
2049
                        $label = null;
2050
                        if (isset($category['attribs']['']['term']))
2051
                        {
2052
                                $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2053
                        }
2054
                        if (isset($category['attribs']['']['scheme']))
2055
                        {
2056
                                $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2057
                        }
2058
                        if (isset($category['attribs']['']['label']))
2059
                        {
2060
                                $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2061
                        }
2062
                        $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
2063
                }
2064
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2065
                {
2066
                        // This is really the label, but keep this as the term also for BC.
2067
                        // Label will also work on retrieving because that falls back to term.
2068
                        $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2069
                        if (isset($category['attribs']['']['domain']))
2070
                        {
2071
                                $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2072
                        }
2073
                        else
2074
                        {
2075
                                $scheme = null;
2076
                        }
2077
                        $categories[] = $this->registry->create('Category', array($term, $scheme, null));
2078
                }
2079
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2080
                {
2081
                        $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2082
                }
2083
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2084
                {
2085
                        $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2086
                }
2087

    
2088
                if (!empty($categories))
2089
                {
2090
                        return array_unique($categories);
2091
                }
2092
                else
2093
                {
2094
                        return null;
2095
                }
2096
        }
2097

    
2098
        /**
2099
         * Get an author for the feed
2100
         *
2101
         * @since 1.1
2102
         * @param int $key The author that you want to return.  Remember that arrays begin with 0, not 1
2103
         * @return SimplePie_Author|null
2104
         */
2105
        public function get_author($key = 0)
2106
        {
2107
                $authors = $this->get_authors();
2108
                if (isset($authors[$key]))
2109
                {
2110
                        return $authors[$key];
2111
                }
2112
                else
2113
                {
2114
                        return null;
2115
                }
2116
        }
2117

    
2118
        /**
2119
         * Get all authors for the feed
2120
         *
2121
         * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
2122
         *
2123
         * @since 1.1
2124
         * @return array|null List of {@see SimplePie_Author} objects
2125
         */
2126
        public function get_authors()
2127
        {
2128
                $authors = array();
2129
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2130
                {
2131
                        $name = null;
2132
                        $uri = null;
2133
                        $email = null;
2134
                        if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2135
                        {
2136
                                $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2137
                        }
2138
                        if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2139
                        {
2140
                                $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]));
2141
                        }
2142
                        if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2143
                        {
2144
                                $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2145
                        }
2146
                        if ($name !== null || $email !== null || $uri !== null)
2147
                        {
2148
                                $authors[] = $this->registry->create('Author', array($name, $uri, $email));
2149
                        }
2150
                }
2151
                if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2152
                {
2153
                        $name = null;
2154
                        $url = null;
2155
                        $email = null;
2156
                        if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2157
                        {
2158
                                $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2159
                        }
2160
                        if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2161
                        {
2162
                                $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]));
2163
                        }
2164
                        if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2165
                        {
2166
                                $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2167
                        }
2168
                        if ($name !== null || $email !== null || $url !== null)
2169
                        {
2170
                                $authors[] = $this->registry->create('Author', array($name, $url, $email));
2171
                        }
2172
                }
2173
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2174
                {
2175
                        $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2176
                }
2177
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2178
                {
2179
                        $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2180
                }
2181
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2182
                {
2183
                        $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2184
                }
2185

    
2186
                if (!empty($authors))
2187
                {
2188
                        return array_unique($authors);
2189
                }
2190
                else
2191
                {
2192
                        return null;
2193
                }
2194
        }
2195

    
2196
        /**
2197
         * Get a contributor for the feed
2198
         *
2199
         * @since 1.1
2200
         * @param int $key The contrbutor that you want to return.  Remember that arrays begin with 0, not 1
2201
         * @return SimplePie_Author|null
2202
         */
2203
        public function get_contributor($key = 0)
2204
        {
2205
                $contributors = $this->get_contributors();
2206
                if (isset($contributors[$key]))
2207
                {
2208
                        return $contributors[$key];
2209
                }
2210
                else
2211
                {
2212
                        return null;
2213
                }
2214
        }
2215

    
2216
        /**
2217
         * Get all contributors for the feed
2218
         *
2219
         * Uses `<atom:contributor>`
2220
         *
2221
         * @since 1.1
2222
         * @return array|null List of {@see SimplePie_Author} objects
2223
         */
2224
        public function get_contributors()
2225
        {
2226
                $contributors = array();
2227
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2228
                {
2229
                        $name = null;
2230
                        $uri = null;
2231
                        $email = null;
2232
                        if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2233
                        {
2234
                                $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2235
                        }
2236
                        if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2237
                        {
2238
                                $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]));
2239
                        }
2240
                        if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2241
                        {
2242
                                $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2243
                        }
2244
                        if ($name !== null || $email !== null || $uri !== null)
2245
                        {
2246
                                $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
2247
                        }
2248
                }
2249
                foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2250
                {
2251
                        $name = null;
2252
                        $url = null;
2253
                        $email = null;
2254
                        if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2255
                        {
2256
                                $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2257
                        }
2258
                        if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2259
                        {
2260
                                $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]));
2261
                        }
2262
                        if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2263
                        {
2264
                                $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2265
                        }
2266
                        if ($name !== null || $email !== null || $url !== null)
2267
                        {
2268
                                $contributors[] = $this->registry->create('Author', array($name, $url, $email));
2269
                        }
2270
                }
2271

    
2272
                if (!empty($contributors))
2273
                {
2274
                        return array_unique($contributors);
2275
                }
2276
                else
2277
                {
2278
                        return null;
2279
                }
2280
        }
2281

    
2282
        /**
2283
         * Get a single link for the feed
2284
         *
2285
         * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2286
         * @param int $key The link that you want to return.  Remember that arrays begin with 0, not 1
2287
         * @param string $rel The relationship of the link to return
2288
         * @return string|null Link URL
2289
         */
2290
        public function get_link($key = 0, $rel = 'alternate')
2291
        {
2292
                $links = $this->get_links($rel);
2293
                if (isset($links[$key]))
2294
                {
2295
                        return $links[$key];
2296
                }
2297
                else
2298
                {
2299
                        return null;
2300
                }
2301
        }
2302

    
2303
        /**
2304
         * Get the permalink for the item
2305
         *
2306
         * Returns the first link available with a relationship of "alternate".
2307
         * Identical to {@see get_link()} with key 0
2308
         *
2309
         * @see get_link
2310
         * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2311
         * @internal Added for parity between the parent-level and the item/entry-level.
2312
         * @return string|null Link URL
2313
         */
2314
        public function get_permalink()
2315
        {
2316
                return $this->get_link(0);
2317
        }
2318

    
2319
        /**
2320
         * Get all links for the feed
2321
         *
2322
         * Uses `<atom:link>` or `<link>`
2323
         *
2324
         * @since Beta 2
2325
         * @param string $rel The relationship of links to return
2326
         * @return array|null Links found for the feed (strings)
2327
         */
2328
        public function get_links($rel = 'alternate')
2329
        {
2330
                if (!isset($this->data['links']))
2331
                {
2332
                        $this->data['links'] = array();
2333
                        if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, '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
                        if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2345
                        {
2346
                                foreach ($links as $link)
2347
                                {
2348
                                        if (isset($link['attribs']['']['href']))
2349
                                        {
2350
                                                $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2351
                                                $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2352

    
2353
                                        }
2354
                                }
2355
                        }
2356
                        if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2357
                        {
2358
                                $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2359
                        }
2360
                        if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2361
                        {
2362
                                $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2363
                        }
2364
                        if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2365
                        {
2366
                                $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2367
                        }
2368

    
2369
                        $keys = array_keys($this->data['links']);
2370
                        foreach ($keys as $key)
2371
                        {
2372
                                if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
2373
                                {
2374
                                        if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2375
                                        {
2376
                                                $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2377
                                                $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2378
                                        }
2379
                                        else
2380
                                        {
2381
                                                $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2382
                                        }
2383
                                }
2384
                                elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2385
                                {
2386
                                        $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2387
                                }
2388
                                $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2389
                        }
2390
                }
2391

    
2392
                if (isset($this->data['links'][$rel]))
2393
                {
2394
                        return $this->data['links'][$rel];
2395
                }
2396
                else
2397
                {
2398
                        return null;
2399
                }
2400
        }
2401

    
2402
        public function get_all_discovered_feeds()
2403
        {
2404
                return $this->all_discovered_feeds;
2405
        }
2406

    
2407
        /**
2408
         * Get the content for the item
2409
         *
2410
         * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
2411
         * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
2412
         *
2413
         * @since 1.0 (previously called `get_feed_description()` since 0.8)
2414
         * @return string|null
2415
         */
2416
        public function get_description()
2417
        {
2418
                if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2419
                {
2420
                        return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2421
                }
2422
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2423
                {
2424
                        return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2425
                }
2426
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2427
                {
2428
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2429
                }
2430
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2431
                {
2432
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2433
                }
2434
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2435
                {
2436
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2437
                }
2438
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2439
                {
2440
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2441
                }
2442
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2443
                {
2444
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2445
                }
2446
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2447
                {
2448
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2449
                }
2450
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2451
                {
2452
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2453
                }
2454
                else
2455
                {
2456
                        return null;
2457
                }
2458
        }
2459

    
2460
        /**
2461
         * Get the copyright info for the feed
2462
         *
2463
         * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
2464
         *
2465
         * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
2466
         * @return string|null
2467
         */
2468
        public function get_copyright()
2469
        {
2470
                if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2471
                {
2472
                        return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2473
                }
2474
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2475
                {
2476
                        return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2477
                }
2478
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2479
                {
2480
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2481
                }
2482
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2483
                {
2484
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2485
                }
2486
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2487
                {
2488
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2489
                }
2490
                else
2491
                {
2492
                        return null;
2493
                }
2494
        }
2495

    
2496
        /**
2497
         * Get the language for the feed
2498
         *
2499
         * Uses `<language>`, `<dc:language>`, or @xml_lang
2500
         *
2501
         * @since 1.0 (previously called `get_feed_language()` since 0.8)
2502
         * @return string|null
2503
         */
2504
        public function get_language()
2505
        {
2506
                if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2507
                {
2508
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2509
                }
2510
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2511
                {
2512
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2513
                }
2514
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2515
                {
2516
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2517
                }
2518
                elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2519
                {
2520
                        return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2521
                }
2522
                elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2523
                {
2524
                        return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2525
                }
2526
                elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2527
                {
2528
                        return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2529
                }
2530
                elseif (isset($this->data['headers']['content-language']))
2531
                {
2532
                        return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2533
                }
2534
                else
2535
                {
2536
                        return null;
2537
                }
2538
        }
2539

    
2540
        /**
2541
         * Get the latitude coordinates for the item
2542
         *
2543
         * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2544
         *
2545
         * Uses `<geo:lat>` or `<georss:point>`
2546
         *
2547
         * @since 1.0
2548
         * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2549
         * @link http://www.georss.org/ GeoRSS
2550
         * @return string|null
2551
         */
2552
        public function get_latitude()
2553
        {
2554

    
2555
                if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2556
                {
2557
                        return (float) $return[0]['data'];
2558
                }
2559
                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))
2560
                {
2561
                        return (float) $match[1];
2562
                }
2563
                else
2564
                {
2565
                        return null;
2566
                }
2567
        }
2568

    
2569
        /**
2570
         * Get the longitude coordinates for the feed
2571
         *
2572
         * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2573
         *
2574
         * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2575
         *
2576
         * @since 1.0
2577
         * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2578
         * @link http://www.georss.org/ GeoRSS
2579
         * @return string|null
2580
         */
2581
        public function get_longitude()
2582
        {
2583
                if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2584
                {
2585
                        return (float) $return[0]['data'];
2586
                }
2587
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2588
                {
2589
                        return (float) $return[0]['data'];
2590
                }
2591
                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))
2592
                {
2593
                        return (float) $match[2];
2594
                }
2595
                else
2596
                {
2597
                        return null;
2598
                }
2599
        }
2600

    
2601
        /**
2602
         * Get the feed logo's title
2603
         *
2604
         * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
2605
         *
2606
         * Uses `<image><title>` or `<image><dc:title>`
2607
         *
2608
         * @return string|null
2609
         */
2610
        public function get_image_title()
2611
        {
2612
                if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2613
                {
2614
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2615
                }
2616
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2617
                {
2618
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2619
                }
2620
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2621
                {
2622
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2623
                }
2624
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2625
                {
2626
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2627
                }
2628
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2629
                {
2630
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2631
                }
2632
                else
2633
                {
2634
                        return null;
2635
                }
2636
        }
2637

    
2638
        /**
2639
         * Get the feed logo's URL
2640
         *
2641
         * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
2642
         * have a "feed logo" URL. This points directly to the image itself.
2643
         *
2644
         * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2645
         * `<image><title>` or `<image><dc:title>`
2646
         *
2647
         * @return string|null
2648
         */
2649
        public function get_image_url()
2650
        {
2651
                if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2652
                {
2653
                        return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2654
                }
2655
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2656
                {
2657
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2658
                }
2659
                elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2660
                {
2661
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2662
                }
2663
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2664
                {
2665
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2666
                }
2667
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2668
                {
2669
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2670
                }
2671
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2672
                {
2673
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2674
                }
2675
                else
2676
                {
2677
                        return null;
2678
                }
2679
        }
2680

    
2681

    
2682
        /**
2683
         * Get the feed logo's link
2684
         *
2685
         * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
2686
         * points to a human-readable page that the image should link to.
2687
         *
2688
         * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2689
         * `<image><title>` or `<image><dc:title>`
2690
         *
2691
         * @return string|null
2692
         */
2693
        public function get_image_link()
2694
        {
2695
                if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2696
                {
2697
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2698
                }
2699
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2700
                {
2701
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2702
                }
2703
                elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2704
                {
2705
                        return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2706
                }
2707
                else
2708
                {
2709
                        return null;
2710
                }
2711
        }
2712

    
2713
        /**
2714
         * Get the feed logo's link
2715
         *
2716
         * RSS 2.0 feeds are allowed to have a "feed logo" width.
2717
         *
2718
         * Uses `<image><width>` or defaults to 88.0 if no width is specified and
2719
         * the feed is an RSS 2.0 feed.
2720
         *
2721
         * @return int|float|null
2722
         */
2723
        public function get_image_width()
2724
        {
2725
                if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2726
                {
2727
                        return round($return[0]['data']);
2728
                }
2729
                elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2730
                {
2731
                        return 88.0;
2732
                }
2733
                else
2734
                {
2735
                        return null;
2736
                }
2737
        }
2738

    
2739
        /**
2740
         * Get the feed logo's height
2741
         *
2742
         * RSS 2.0 feeds are allowed to have a "feed logo" height.
2743
         *
2744
         * Uses `<image><height>` or defaults to 31.0 if no height is specified and
2745
         * the feed is an RSS 2.0 feed.
2746
         *
2747
         * @return int|float|null
2748
         */
2749
        public function get_image_height()
2750
        {
2751
                if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2752
                {
2753
                        return round($return[0]['data']);
2754
                }
2755
                elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2756
                {
2757
                        return 31.0;
2758
                }
2759
                else
2760
                {
2761
                        return null;
2762
                }
2763
        }
2764

    
2765
        /**
2766
         * Get the number of items in the feed
2767
         *
2768
         * This is well-suited for {@link http://php.net/for for()} loops with
2769
         * {@see get_item()}
2770
         *
2771
         * @param int $max Maximum value to return. 0 for no limit
2772
         * @return int Number of items in the feed
2773
         */
2774
        public function get_item_quantity($max = 0)
2775
        {
2776
                $max = (int) $max;
2777
                $qty = count($this->get_items());
2778
                if ($max === 0)
2779
                {
2780
                        return $qty;
2781
                }
2782
                else
2783
                {
2784
                        return ($qty > $max) ? $max : $qty;
2785
                }
2786
        }
2787

    
2788
        /**
2789
         * Get a single item from the feed
2790
         *
2791
         * This is better suited for {@link http://php.net/for for()} loops, whereas
2792
         * {@see get_items()} is better suited for
2793
         * {@link http://php.net/foreach foreach()} loops.
2794
         *
2795
         * @see get_item_quantity()
2796
         * @since Beta 2
2797
         * @param int $key The item that you want to return.  Remember that arrays begin with 0, not 1
2798
         * @return SimplePie_Item|null
2799
         */
2800
        public function get_item($key = 0)
2801
        {
2802
                $items = $this->get_items();
2803
                if (isset($items[$key]))
2804
                {
2805
                        return $items[$key];
2806
                }
2807
                else
2808
                {
2809
                        return null;
2810
                }
2811
        }
2812

    
2813
        /**
2814
         * Get all items from the feed
2815
         *
2816
         * This is better suited for {@link http://php.net/for for()} loops, whereas
2817
         * {@see get_items()} is better suited for
2818
         * {@link http://php.net/foreach foreach()} loops.
2819
         *
2820
         * @see get_item_quantity
2821
         * @since Beta 2
2822
         * @param int $start Index to start at
2823
         * @param int $end Number of items to return. 0 for all items after `$start`
2824
         * @return array|null List of {@see SimplePie_Item} objects
2825
         */
2826
        public function get_items($start = 0, $end = 0)
2827
        {
2828
                if (!isset($this->data['items']))
2829
                {
2830
                        if (!empty($this->multifeed_objects))
2831
                        {
2832
                                $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
2833
                        }
2834
                        else
2835
                        {
2836
                                $this->data['items'] = array();
2837
                                if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
2838
                                {
2839
                                        $keys = array_keys($items);
2840
                                        foreach ($keys as $key)
2841
                                        {
2842
                                                $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2843
                                        }
2844
                                }
2845
                                if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
2846
                                {
2847
                                        $keys = array_keys($items);
2848
                                        foreach ($keys as $key)
2849
                                        {
2850
                                                $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2851
                                        }
2852
                                }
2853
                                if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
2854
                                {
2855
                                        $keys = array_keys($items);
2856
                                        foreach ($keys as $key)
2857
                                        {
2858
                                                $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2859
                                        }
2860
                                }
2861
                                if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2862
                                {
2863
                                        $keys = array_keys($items);
2864
                                        foreach ($keys as $key)
2865
                                        {
2866
                                                $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2867
                                        }
2868
                                }
2869
                                if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
2870
                                {
2871
                                        $keys = array_keys($items);
2872
                                        foreach ($keys as $key)
2873
                                        {
2874
                                                $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2875
                                        }
2876
                                }
2877
                        }
2878
                }
2879

    
2880
                if (!empty($this->data['items']))
2881
                {
2882
                        // If we want to order it by date, check if all items have a date, and then sort it
2883
                        if ($this->order_by_date && empty($this->multifeed_objects))
2884
                        {
2885
                                if (!isset($this->data['ordered_items']))
2886
                                {
2887
                                        $do_sort = true;
2888
                                        foreach ($this->data['items'] as $item)
2889
                                        {
2890
                                                if (!$item->get_date('U'))
2891
                                                {
2892
                                                        $do_sort = false;
2893
                                                        break;
2894
                                                }
2895
                                        }
2896
                                        $item = null;
2897
                                        $this->data['ordered_items'] = $this->data['items'];
2898
                                        if ($do_sort)
2899
                                        {
2900
                                                usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
2901
                                        }
2902
                                }
2903
                                $items = $this->data['ordered_items'];
2904
                        }
2905
                        else
2906
                        {
2907
                                $items = $this->data['items'];
2908
                        }
2909

    
2910
                        // Slice the data as desired
2911
                        if ($end === 0)
2912
                        {
2913
                                return array_slice($items, $start);
2914
                        }
2915
                        else
2916
                        {
2917
                                return array_slice($items, $start, $end);
2918
                        }
2919
                }
2920
                else
2921
                {
2922
                        return array();
2923
                }
2924
        }
2925

    
2926
        /**
2927
         * Set the favicon handler
2928
         *
2929
         * @deprecated Use your own favicon handling instead
2930
         */
2931
        public function set_favicon_handler($page = false, $qs = 'i')
2932
        {
2933
                $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2934
                trigger_error('Favicon handling has been removed, please use your own handling', $level);
2935
                return false;
2936
        }
2937

    
2938
        /**
2939
         * Get the favicon for the current feed
2940
         *
2941
         * @deprecated Use your own favicon handling instead
2942
         */
2943
        public function get_favicon()
2944
        {
2945
                $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2946
                trigger_error('Favicon handling has been removed, please use your own handling', $level);
2947

    
2948
                if (($url = $this->get_link()) !== null)
2949
                {
2950
                        return 'http://g.etfv.co/' . urlencode($url);
2951
                }
2952

    
2953
                return false;
2954
        }
2955

    
2956
        /**
2957
         * Magic method handler
2958
         *
2959
         * @param string $method Method name
2960
         * @param array $args Arguments to the method
2961
         * @return mixed
2962
         */
2963
        public function __call($method, $args)
2964
        {
2965
                if (strpos($method, 'subscribe_') === 0)
2966
                {
2967
                        $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2968
                        trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
2969
                        return '';
2970
                }
2971
                if ($method === 'enable_xml_dump')
2972
                {
2973
                        $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2974
                        trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
2975
                        return false;
2976
                }
2977

    
2978
                $class = get_class($this);
2979
                $trace = debug_backtrace();
2980
                $file = $trace[0]['file'];
2981
                $line = $trace[0]['line'];
2982
                trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
2983
        }
2984

    
2985
        /**
2986
         * Sorting callback for items
2987
         *
2988
         * @access private
2989
         * @param SimplePie $a
2990
         * @param SimplePie $b
2991
         * @return boolean
2992
         */
2993
        public static function sort_items($a, $b)
2994
        {
2995
                return $a->get_date('U') <= $b->get_date('U');
2996
        }
2997

    
2998
        /**
2999
         * Merge items from several feeds into one
3000
         *
3001
         * If you're merging multiple feeds together, they need to all have dates
3002
         * for the items or else SimplePie will refuse to sort them.
3003
         *
3004
         * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
3005
         * @param array $urls List of SimplePie feed objects to merge
3006
         * @param int $start Starting item
3007
         * @param int $end Number of items to return
3008
         * @param int $limit Maximum number of items per feed
3009
         * @return array
3010
         */
3011
        public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
3012
        {
3013
                if (is_array($urls) && sizeof($urls) > 0)
3014
                {
3015
                        $items = array();
3016
                        foreach ($urls as $arg)
3017
                        {
3018
                                if ($arg instanceof SimplePie)
3019
                                {
3020
                                        $items = array_merge($items, $arg->get_items(0, $limit));
3021
                                }
3022
                                else
3023
                                {
3024
                                        trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
3025
                                }
3026
                        }
3027

    
3028
                        $do_sort = true;
3029
                        foreach ($items as $item)
3030
                        {
3031
                                if (!$item->get_date('U'))
3032
                                {
3033
                                        $do_sort = false;
3034
                                        break;
3035
                                }
3036
                        }
3037
                        $item = null;
3038
                        if ($do_sort)
3039
                        {
3040
                                usort($items, array(get_class($urls[0]), 'sort_items'));
3041
                        }
3042

    
3043
                        if ($end === 0)
3044
                        {
3045
                                return array_slice($items, $start);
3046
                        }
3047
                        else
3048
                        {
3049
                                return array_slice($items, $start, $end);
3050
                        }
3051
                }
3052
                else
3053
                {
3054
                        trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
3055
                        return array();
3056
                }
3057
        }
3058
}