]> git.wh0rd.org - tt-rss.git/blame - lib/simplepie/simplepie.inc
update simplepie to 1.3.1 (closes #471)
[tt-rss.git] / lib / simplepie / simplepie.inc
CommitLineData
f2f7b699
AD
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 *
a6e043ff
AD
8 * Please note: This file is automatically generated by a build script. The
9 * full original source is always available from http://simplepie.org/
10 *
11 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
f2f7b699
AD
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without modification, are
15 * permitted provided that the following conditions are met:
16 *
17 * * Redistributions of source code must retain the above copyright notice, this list of
18 * conditions and the following disclaimer.
19 *
20 * * Redistributions in binary form must reproduce the above copyright notice, this list
21 * of conditions and the following disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
25 * to endorse or promote products derived from this software without specific prior
26 * written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
29 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
30 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
31 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 * @package SimplePie
a6e043ff
AD
39 * @version 1.3.1
40 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
f2f7b699
AD
41 * @author Ryan Parman
42 * @author Geoffrey Sneddon
5b085627 43 * @author Ryan McCue
f2f7b699 44 * @link http://simplepie.org/ SimplePie
f2f7b699 45 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
f2f7b699
AD
46 */
47
48/**
49 * SimplePie Name
50 */
51define('SIMPLEPIE_NAME', 'SimplePie');
52
53/**
54 * SimplePie Version
55 */
a6e043ff 56define('SIMPLEPIE_VERSION', '1.3.1');
f2f7b699
AD
57
58/**
59 * SimplePie Build
a6e043ff 60 * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
f2f7b699 61 */
a6e043ff 62define('SIMPLEPIE_BUILD', '20121030175911');
f2f7b699
AD
63
64/**
65 * SimplePie Website URL
66 */
6d7d21a0 67define('SIMPLEPIE_URL', 'http://simplepie.org');
f2f7b699
AD
68
69/**
70 * SimplePie Useragent
71 * @see SimplePie::set_useragent()
72 */
73define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
74
75/**
76 * SimplePie Linkback
77 */
78define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
79
80/**
81 * No Autodiscovery
82 * @see SimplePie::set_autodiscovery_level()
83 */
84define('SIMPLEPIE_LOCATOR_NONE', 0);
85
86/**
87 * Feed Link Element Autodiscovery
88 * @see SimplePie::set_autodiscovery_level()
89 */
90define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
91
92/**
93 * Local Feed Extension Autodiscovery
94 * @see SimplePie::set_autodiscovery_level()
95 */
96define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
97
98/**
99 * Local Feed Body Autodiscovery
100 * @see SimplePie::set_autodiscovery_level()
101 */
102define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
103
104/**
105 * Remote Feed Extension Autodiscovery
106 * @see SimplePie::set_autodiscovery_level()
107 */
108define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
109
110/**
111 * Remote Feed Body Autodiscovery
112 * @see SimplePie::set_autodiscovery_level()
113 */
114define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
115
116/**
117 * All Feed Autodiscovery
118 * @see SimplePie::set_autodiscovery_level()
119 */
120define('SIMPLEPIE_LOCATOR_ALL', 31);
121
122/**
123 * No known feed type
124 */
125define('SIMPLEPIE_TYPE_NONE', 0);
126
127/**
128 * RSS 0.90
129 */
130define('SIMPLEPIE_TYPE_RSS_090', 1);
131
132/**
133 * RSS 0.91 (Netscape)
134 */
135define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
136
137/**
138 * RSS 0.91 (Userland)
139 */
140define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
141
142/**
143 * RSS 0.91 (both Netscape and Userland)
144 */
145define('SIMPLEPIE_TYPE_RSS_091', 6);
146
147/**
148 * RSS 0.92
149 */
150define('SIMPLEPIE_TYPE_RSS_092', 8);
151
152/**
153 * RSS 0.93
154 */
155define('SIMPLEPIE_TYPE_RSS_093', 16);
156
157/**
158 * RSS 0.94
159 */
160define('SIMPLEPIE_TYPE_RSS_094', 32);
161
162/**
163 * RSS 1.0
164 */
165define('SIMPLEPIE_TYPE_RSS_10', 64);
166
167/**
168 * RSS 2.0
169 */
170define('SIMPLEPIE_TYPE_RSS_20', 128);
171
172/**
173 * RDF-based RSS
174 */
175define('SIMPLEPIE_TYPE_RSS_RDF', 65);
176
177/**
178 * Non-RDF-based RSS (truly intended as syndication format)
179 */
180define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
181
182/**
183 * All RSS
184 */
185define('SIMPLEPIE_TYPE_RSS_ALL', 255);
186
187/**
188 * Atom 0.3
189 */
190define('SIMPLEPIE_TYPE_ATOM_03', 256);
191
192/**
193 * Atom 1.0
194 */
195define('SIMPLEPIE_TYPE_ATOM_10', 512);
196
197/**
198 * All Atom
199 */
200define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
201
202/**
203 * All feed types
204 */
205define('SIMPLEPIE_TYPE_ALL', 1023);
206
207/**
208 * No construct
209 */
210define('SIMPLEPIE_CONSTRUCT_NONE', 0);
211
212/**
213 * Text construct
214 */
215define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
216
217/**
218 * HTML construct
219 */
220define('SIMPLEPIE_CONSTRUCT_HTML', 2);
221
222/**
223 * XHTML construct
224 */
225define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
226
227/**
228 * base64-encoded construct
229 */
230define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
231
232/**
233 * IRI construct
234 */
235define('SIMPLEPIE_CONSTRUCT_IRI', 16);
236
237/**
238 * A construct that might be HTML
239 */
240define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
241
242/**
243 * All constructs
244 */
245define('SIMPLEPIE_CONSTRUCT_ALL', 63);
246
a5ae3915
MK
247/**
248 * Don't change case
249 */
250define('SIMPLEPIE_SAME_CASE', 1);
251
252/**
253 * Change to lowercase
254 */
255define('SIMPLEPIE_LOWERCASE', 2);
256
257/**
258 * Change to uppercase
259 */
260define('SIMPLEPIE_UPPERCASE', 4);
261
f2f7b699
AD
262/**
263 * PCRE for HTML attributes
264 */
6d7d21a0 265define('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]*');
f2f7b699
AD
266
267/**
268 * PCRE for XML attributes
269 */
270define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
271
272/**
273 * XML Namespace
274 */
275define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
276
277/**
278 * Atom 1.0 Namespace
279 */
280define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
281
282/**
283 * Atom 0.3 Namespace
284 */
285define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
286
287/**
288 * RDF Namespace
289 */
290define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
291
292/**
293 * RSS 0.90 Namespace
294 */
295define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
296
297/**
298 * RSS 1.0 Namespace
299 */
300define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
301
302/**
303 * RSS 1.0 Content Module Namespace
304 */
305define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
306
f954bd49
AD
307/**
308 * RSS 2.0 Namespace
309 * (Stupid, I know, but I'm certain it will confuse people less with support.)
310 */
311define('SIMPLEPIE_NAMESPACE_RSS_20', '');
312
f2f7b699
AD
313/**
314 * DC 1.0 Namespace
315 */
316define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
317
318/**
319 * DC 1.1 Namespace
320 */
321define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
322
323/**
324 * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
325 */
326define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
327
328/**
329 * GeoRSS Namespace
330 */
331define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
332
333/**
334 * Media RSS Namespace
335 */
336define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
337
3cae90e1 338/**
a6e043ff 339 * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
3cae90e1
AD
340 */
341define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
342
a6e043ff
AD
343/**
344 * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
345 */
346define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
347
348/**
349 * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
350 */
351define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
352
353/**
354 * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
355 */
356define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
357
358/**
359 * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
360 */
361define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
362
f2f7b699
AD
363/**
364 * iTunes RSS Namespace
365 */
366define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
367
368/**
369 * XHTML Namespace
370 */
371define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
372
373/**
374 * IANA Link Relations Registry
375 */
376define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
377
6d7d21a0
AD
378/**
379 * No file source
380 */
381define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
382
383/**
384 * Remote file source
385 */
386define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
387
388/**
389 * Local file source
390 */
391define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
392
393/**
394 * fsockopen() file source
395 */
396define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
397
398/**
399 * cURL file source
400 */
401define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
402
403/**
404 * file_get_contents() file source
405 */
406define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
407
f2f7b699
AD
408/**
409 * SimplePie
410 *
411 * @package SimplePie
a6e043ff 412 * @subpackage API
f2f7b699
AD
413 */
414class SimplePie
415{
416 /**
417 * @var array Raw data
418 * @access private
419 */
a6e043ff 420 public $data = array();
f2f7b699
AD
421
422 /**
423 * @var mixed Error string
424 * @access private
425 */
a6e043ff 426 public $error;
f2f7b699
AD
427
428 /**
429 * @var object Instance of SimplePie_Sanitize (or other class)
430 * @see SimplePie::set_sanitize_class()
431 * @access private
432 */
a6e043ff 433 public $sanitize;
f2f7b699
AD
434
435 /**
436 * @var string SimplePie Useragent
437 * @see SimplePie::set_useragent()
438 * @access private
439 */
a6e043ff 440 public $useragent = SIMPLEPIE_USERAGENT;
f2f7b699
AD
441
442 /**
443 * @var string Feed URL
444 * @see SimplePie::set_feed_url()
445 * @access private
446 */
a6e043ff 447 public $feed_url;
f2f7b699
AD
448
449 /**
450 * @var object Instance of SimplePie_File to use as a feed
451 * @see SimplePie::set_file()
452 * @access private
453 */
a6e043ff 454 public $file;
f2f7b699
AD
455
456 /**
457 * @var string Raw feed data
458 * @see SimplePie::set_raw_data()
459 * @access private
460 */
a6e043ff 461 public $raw_data;
f2f7b699
AD
462
463 /**
464 * @var int Timeout for fetching remote files
465 * @see SimplePie::set_timeout()
466 * @access private
467 */
a6e043ff 468 public $timeout = 10;
f2f7b699
AD
469
470 /**
471 * @var bool Forces fsockopen() to be used for remote files instead
472 * of cURL, even if a new enough version is installed
473 * @see SimplePie::force_fsockopen()
474 * @access private
475 */
a6e043ff 476 public $force_fsockopen = false;
f2f7b699 477
6d7d21a0
AD
478 /**
479 * @var bool Force the given data/URL to be treated as a feed no matter what
480 * it appears like
481 * @see SimplePie::force_feed()
482 * @access private
483 */
a6e043ff 484 public $force_feed = false;
f2f7b699
AD
485
486 /**
487 * @var bool Enable/Disable Caching
488 * @see SimplePie::enable_cache()
489 * @access private
490 */
a6e043ff 491 public $cache = true;
f2f7b699
AD
492
493 /**
494 * @var int Cache duration (in seconds)
495 * @see SimplePie::set_cache_duration()
496 * @access private
497 */
a6e043ff 498 public $cache_duration = 3600;
f2f7b699
AD
499
500 /**
501 * @var int Auto-discovery cache duration (in seconds)
502 * @see SimplePie::set_autodiscovery_cache_duration()
503 * @access private
504 */
a6e043ff 505 public $autodiscovery_cache_duration = 604800; // 7 Days.
f2f7b699
AD
506
507 /**
508 * @var string Cache location (relative to executing script)
509 * @see SimplePie::set_cache_location()
510 * @access private
511 */
a6e043ff 512 public $cache_location = './cache';
f2f7b699
AD
513
514 /**
515 * @var string Function that creates the cache filename
516 * @see SimplePie::set_cache_name_function()
517 * @access private
518 */
a6e043ff 519 public $cache_name_function = 'md5';
f2f7b699
AD
520
521 /**
522 * @var bool Reorder feed by date descending
523 * @see SimplePie::enable_order_by_date()
524 * @access private
525 */
a6e043ff 526 public $order_by_date = true;
f2f7b699
AD
527
528 /**
529 * @var mixed Force input encoding to be set to the follow value
530 * (false, or anything type-cast to false, disables this feature)
531 * @see SimplePie::set_input_encoding()
532 * @access private
533 */
a6e043ff 534 public $input_encoding = false;
f2f7b699
AD
535
536 /**
537 * @var int Feed Autodiscovery Level
538 * @see SimplePie::set_autodiscovery_level()
539 * @access private
540 */
a6e043ff 541 public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
6d7d21a0 542
f2f7b699 543 /**
a6e043ff
AD
544 * Class registry object
545 *
546 * @var SimplePie_Registry
f2f7b699 547 */
a6e043ff 548 public $registry;
f2f7b699
AD
549
550 /**
551 * @var int Maximum number of feeds to check with autodiscovery
552 * @see SimplePie::set_max_checked_feeds()
553 * @access private
554 */
a6e043ff 555 public $max_checked_feeds = 10;
f2f7b699 556
a5ae3915
MK
557 /**
558 * @var array All the feeds found during the autodiscovery process
559 * @see SimplePie::get_all_discovered_feeds()
560 * @access private
561 */
a6e043ff 562 public $all_discovered_feeds = array();
f2f7b699
AD
563
564 /**
565 * @var string Web-accessible path to the handler_image.php file.
566 * @see SimplePie::set_image_handler()
567 * @access private
568 */
a6e043ff 569 public $image_handler = '';
f2f7b699
AD
570
571 /**
572 * @var array Stores the URLs when multiple feeds are being initialized.
573 * @see SimplePie::set_feed_url()
574 * @access private
575 */
a6e043ff 576 public $multifeed_url = array();
f2f7b699
AD
577
578 /**
579 * @var array Stores SimplePie objects when multiple feeds initialized.
580 * @access private
581 */
a6e043ff 582 public $multifeed_objects = array();
f2f7b699
AD
583
584 /**
585 * @var array Stores the get_object_vars() array for use with multifeeds.
586 * @see SimplePie::set_feed_url()
587 * @access private
588 */
a6e043ff 589 public $config_settings = null;
f2f7b699 590
6d7d21a0
AD
591 /**
592 * @var integer Stores the number of items to return per-feed with multifeeds.
593 * @see SimplePie::set_item_limit()
594 * @access private
595 */
a6e043ff 596 public $item_limit = 0;
6d7d21a0 597
f2f7b699
AD
598 /**
599 * @var array Stores the default attributes to be stripped by strip_attributes().
600 * @see SimplePie::strip_attributes()
601 * @access private
602 */
a6e043ff 603 public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
f2f7b699
AD
604
605 /**
606 * @var array Stores the default tags to be stripped by strip_htmltags().
607 * @see SimplePie::strip_htmltags()
608 * @access private
609 */
a6e043ff 610 public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
f2f7b699
AD
611
612 /**
613 * The SimplePie class contains feed level data and options
614 *
a6e043ff
AD
615 * To use SimplePie, create the SimplePie object with no parameters. You can
616 * then set configuration options using the provided methods. After setting
f2f7b699 617 * them, you must initialise the feed using $feed->init(). At that point the
a6e043ff
AD
618 * object's methods and properties will be available to you.
619 *
620 * Previously, it was possible to pass in the feed URL along with cache
621 * options directly into the constructor. This has been removed as of 1.3 as
622 * it caused a lot of confusion.
f2f7b699 623 *
f2f7b699 624 * @since 1.0 Preview Release
f2f7b699 625 */
a6e043ff 626 public function __construct()
f2f7b699 627 {
a6e043ff 628 if (version_compare(PHP_VERSION, '5.2', '<'))
f2f7b699 629 {
a6e043ff
AD
630 trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
631 die();
f2f7b699
AD
632 }
633
a6e043ff
AD
634 // Other objects, instances created here so we can set options on them
635 $this->sanitize = new SimplePie_Sanitize();
636 $this->registry = new SimplePie_Registry();
f2f7b699 637
a6e043ff 638 if (func_num_args() > 0)
f2f7b699 639 {
a6e043ff
AD
640 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
641 trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
642
643 $args = func_get_args();
644 switch (count($args)) {
645 case 3:
646 $this->set_cache_duration($args[2]);
647 case 2:
648 $this->set_cache_location($args[1]);
649 case 1:
650 $this->set_feed_url($args[0]);
651 $this->init();
652 }
f2f7b699
AD
653 }
654 }
655
656 /**
657 * Used for converting object to a string
658 */
a6e043ff 659 public function __toString()
f2f7b699
AD
660 {
661 return md5(serialize($this->data));
662 }
f954bd49 663
6d7d21a0
AD
664 /**
665 * Remove items that link back to this before destroying this object
666 */
a6e043ff 667 public function __destruct()
6d7d21a0 668 {
a5ae3915 669 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
6d7d21a0 670 {
a5ae3915 671 if (!empty($this->data['items']))
6d7d21a0 672 {
a5ae3915
MK
673 foreach ($this->data['items'] as $item)
674 {
675 $item->__destruct();
676 }
677 unset($item, $this->data['items']);
6d7d21a0 678 }
a5ae3915 679 if (!empty($this->data['ordered_items']))
6d7d21a0 680 {
a5ae3915
MK
681 foreach ($this->data['ordered_items'] as $item)
682 {
683 $item->__destruct();
684 }
685 unset($item, $this->data['ordered_items']);
6d7d21a0 686 }
6d7d21a0
AD
687 }
688 }
f954bd49 689
6d7d21a0 690 /**
a6e043ff
AD
691 * Force the given data/URL to be treated as a feed
692 *
693 * This tells SimplePie to ignore the content-type provided by the server.
694 * Be careful when using this option, as it will also disable autodiscovery.
6d7d21a0 695 *
6d7d21a0
AD
696 * @since 1.1
697 * @param bool $enable Force the given data/URL to be treated as a feed
698 */
a6e043ff 699 public function force_feed($enable = false)
6d7d21a0
AD
700 {
701 $this->force_feed = (bool) $enable;
702 }
f2f7b699
AD
703
704 /**
a6e043ff 705 * Set the URL of the feed you want to parse
f2f7b699
AD
706 *
707 * This allows you to enter the URL of the feed you want to parse, or the
708 * website you want to try to use auto-discovery on. This takes priority
709 * over any set raw data.
710 *
711 * You can set multiple feeds to mash together by passing an array instead
712 * of a string for the $url. Remember that with each additional feed comes
713 * additional processing and resources.
714 *
f2f7b699 715 * @since 1.0 Preview Release
a6e043ff
AD
716 * @see set_raw_data()
717 * @param string|array $url This is the URL (or array of URLs) that you want to parse.
f2f7b699 718 */
a6e043ff 719 public function set_feed_url($url)
f2f7b699 720 {
a6e043ff 721 $this->multifeed_url = array();
f2f7b699
AD
722 if (is_array($url))
723 {
f2f7b699
AD
724 foreach ($url as $value)
725 {
a6e043ff 726 $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
f2f7b699
AD
727 }
728 }
729 else
730 {
a6e043ff 731 $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
f2f7b699
AD
732 }
733 }
734
735 /**
a6e043ff 736 * Set an instance of {@see SimplePie_File} to use as a feed
f2f7b699 737 *
a6e043ff 738 * @param SimplePie_File &$file
f2f7b699
AD
739 * @return bool True on success, false on failure
740 */
a6e043ff 741 public function set_file(&$file)
f2f7b699 742 {
a6e043ff 743 if ($file instanceof SimplePie_File)
f2f7b699
AD
744 {
745 $this->feed_url = $file->url;
746 $this->file =& $file;
747 return true;
748 }
749 return false;
750 }
751
752 /**
a6e043ff
AD
753 * Set the raw XML data to parse
754 *
f2f7b699
AD
755 * Allows you to use a string of RSS/Atom data instead of a remote feed.
756 *
757 * If you have a feed available as a string in PHP, you can tell SimplePie
758 * to parse that data string instead of a remote feed. Any set feed URL
759 * takes precedence.
760 *
f2f7b699
AD
761 * @since 1.0 Beta 3
762 * @param string $data RSS or Atom data as a string.
a6e043ff 763 * @see set_feed_url()
f2f7b699 764 */
a6e043ff 765 public function set_raw_data($data)
f2f7b699 766 {
3cae90e1 767 $this->raw_data = $data;
f2f7b699
AD
768 }
769
770 /**
a6e043ff 771 * Set the the default timeout for fetching remote feeds
f2f7b699
AD
772 *
773 * This allows you to change the maximum time the feed's server to respond
774 * and send the feed back.
775 *
f2f7b699
AD
776 * @since 1.0 Beta 3
777 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
778 */
a6e043ff 779 public function set_timeout($timeout = 10)
f2f7b699
AD
780 {
781 $this->timeout = (int) $timeout;
782 }
783
784 /**
a6e043ff 785 * Force SimplePie to use fsockopen() instead of cURL
f2f7b699 786 *
f2f7b699
AD
787 * @since 1.0 Beta 3
788 * @param bool $enable Force fsockopen() to be used
789 */
a6e043ff 790 public function force_fsockopen($enable = false)
f2f7b699
AD
791 {
792 $this->force_fsockopen = (bool) $enable;
793 }
794
795 /**
a6e043ff 796 * Enable/disable caching in SimplePie.
f2f7b699
AD
797 *
798 * This option allows you to disable caching all-together in SimplePie.
799 * However, disabling the cache can lead to longer load times.
800 *
f2f7b699
AD
801 * @since 1.0 Preview Release
802 * @param bool $enable Enable caching
803 */
a6e043ff 804 public function enable_cache($enable = true)
f2f7b699
AD
805 {
806 $this->cache = (bool) $enable;
807 }
808
809 /**
a6e043ff
AD
810 * Set the length of time (in seconds) that the contents of a feed will be
811 * cached
f2f7b699 812 *
a6e043ff 813 * @param int $seconds The feed content cache duration
f2f7b699 814 */
a6e043ff 815 public function set_cache_duration($seconds = 3600)
f2f7b699
AD
816 {
817 $this->cache_duration = (int) $seconds;
818 }
819
820 /**
a6e043ff
AD
821 * Set the length of time (in seconds) that the autodiscovered feed URL will
822 * be cached
f2f7b699 823 *
f2f7b699
AD
824 * @param int $seconds The autodiscovered feed URL cache duration.
825 */
a6e043ff 826 public function set_autodiscovery_cache_duration($seconds = 604800)
f2f7b699
AD
827 {
828 $this->autodiscovery_cache_duration = (int) $seconds;
829 }
830
831 /**
a6e043ff 832 * Set the file system location where the cached files should be stored
f2f7b699 833 *
f2f7b699
AD
834 * @param string $location The file system location.
835 */
a6e043ff 836 public function set_cache_location($location = './cache')
f2f7b699
AD
837 {
838 $this->cache_location = (string) $location;
839 }
840
841 /**
a6e043ff 842 * Set whether feed items should be sorted into reverse chronological order
f2f7b699 843 *
f2f7b699
AD
844 * @param bool $enable Sort as reverse chronological order.
845 */
a6e043ff 846 public function enable_order_by_date($enable = true)
f2f7b699
AD
847 {
848 $this->order_by_date = (bool) $enable;
849 }
850
851 /**
a6e043ff 852 * Set the character encoding used to parse the feed
f2f7b699 853 *
a6e043ff
AD
854 * This overrides the encoding reported by the feed, however it will fall
855 * back to the normal encoding detection if the override fails
856 *
857 * @param string $encoding Character encoding
f2f7b699 858 */
a6e043ff 859 public function set_input_encoding($encoding = false)
f2f7b699
AD
860 {
861 if ($encoding)
862 {
863 $this->input_encoding = (string) $encoding;
864 }
865 else
866 {
867 $this->input_encoding = false;
868 }
869 }
870
871 /**
872 * Set how much feed autodiscovery to do
873 *
f2f7b699
AD
874 * @see SIMPLEPIE_LOCATOR_NONE
875 * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
876 * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
877 * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
878 * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
879 * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
880 * @see SIMPLEPIE_LOCATOR_ALL
a6e043ff 881 * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
f2f7b699 882 */
a6e043ff 883 public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
f2f7b699
AD
884 {
885 $this->autodiscovery = (int) $level;
886 }
887
888 /**
a6e043ff 889 * Get the class registry
f2f7b699 890 *
a6e043ff
AD
891 * Use this to override SimplePie's default classes
892 * @see SimplePie_Registry
893 * @return SimplePie_Registry
f2f7b699 894 */
a6e043ff 895 public function &get_registry()
f2f7b699 896 {
a6e043ff 897 return $this->registry;
f2f7b699
AD
898 }
899
a6e043ff 900 /**#@+
f2f7b699
AD
901 * Useful when you are overloading or extending SimplePie's default classes.
902 *
a6e043ff 903 * @deprecated Use {@see get_registry()} instead
f2f7b699 904 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
a6e043ff
AD
905 * @param string $class Name of custom class
906 * @return boolean True on success, false otherwise
907 */
908 /**
909 * Set which class SimplePie uses for caching
f2f7b699 910 */
a6e043ff 911 public function set_cache_class($class = 'SimplePie_Cache')
f2f7b699 912 {
a6e043ff 913 return $this->registry->register('Cache', $class, true);
f2f7b699
AD
914 }
915
916 /**
a6e043ff 917 * Set which class SimplePie uses for auto-discovery
f2f7b699 918 */
a6e043ff 919 public function set_locator_class($class = 'SimplePie_Locator')
f2f7b699 920 {
a6e043ff 921 return $this->registry->register('Locator', $class, true);
f2f7b699
AD
922 }
923
924 /**
a6e043ff 925 * Set which class SimplePie uses for XML parsing
f2f7b699 926 */
a6e043ff 927 public function set_parser_class($class = 'SimplePie_Parser')
f2f7b699 928 {
a6e043ff 929 return $this->registry->register('Parser', $class, true);
f2f7b699
AD
930 }
931
932 /**
a6e043ff 933 * Set which class SimplePie uses for remote file fetching
f2f7b699 934 */
a6e043ff 935 public function set_file_class($class = 'SimplePie_File')
f2f7b699 936 {
a6e043ff 937 return $this->registry->register('File', $class, true);
f2f7b699
AD
938 }
939
940 /**
a6e043ff 941 * Set which class SimplePie uses for data sanitization
f2f7b699 942 */
a6e043ff 943 public function set_sanitize_class($class = 'SimplePie_Sanitize')
f2f7b699 944 {
a6e043ff 945 return $this->registry->register('Sanitize', $class, true);
f2f7b699
AD
946 }
947
948 /**
a6e043ff 949 * Set which class SimplePie uses for handling feed items
f2f7b699 950 */
a6e043ff 951 public function set_item_class($class = 'SimplePie_Item')
f2f7b699 952 {
a6e043ff 953 return $this->registry->register('Item', $class, true);
f2f7b699
AD
954 }
955
956 /**
a6e043ff 957 * Set which class SimplePie uses for handling author data
f2f7b699 958 */
a6e043ff 959 public function set_author_class($class = 'SimplePie_Author')
f2f7b699 960 {
a6e043ff 961 return $this->registry->register('Author', $class, true);
f2f7b699
AD
962 }
963
964 /**
a6e043ff 965 * Set which class SimplePie uses for handling category data
f2f7b699 966 */
a6e043ff 967 public function set_category_class($class = 'SimplePie_Category')
f2f7b699 968 {
a6e043ff 969 return $this->registry->register('Category', $class, true);
f2f7b699
AD
970 }
971
972 /**
a6e043ff 973 * Set which class SimplePie uses for feed enclosures
f2f7b699 974 */
a6e043ff 975 public function set_enclosure_class($class = 'SimplePie_Enclosure')
f2f7b699 976 {
a6e043ff 977 return $this->registry->register('Enclosure', $class, true);
f2f7b699
AD
978 }
979
980 /**
a6e043ff 981 * Set which class SimplePie uses for `<media:text>` captions
f2f7b699 982 */
a6e043ff 983 public function set_caption_class($class = 'SimplePie_Caption')
f2f7b699 984 {
a6e043ff 985 return $this->registry->register('Caption', $class, true);
f2f7b699
AD
986 }
987
988 /**
a6e043ff 989 * Set which class SimplePie uses for `<media:copyright>`
f2f7b699 990 */
a6e043ff 991 public function set_copyright_class($class = 'SimplePie_Copyright')
f2f7b699 992 {
a6e043ff 993 return $this->registry->register('Copyright', $class, true);
f2f7b699
AD
994 }
995
996 /**
a6e043ff 997 * Set which class SimplePie uses for `<media:credit>`
f2f7b699 998 */
a6e043ff 999 public function set_credit_class($class = 'SimplePie_Credit')
f2f7b699 1000 {
a6e043ff 1001 return $this->registry->register('Credit', $class, true);
f2f7b699
AD
1002 }
1003
1004 /**
a6e043ff 1005 * Set which class SimplePie uses for `<media:rating>`
f2f7b699 1006 */
a6e043ff 1007 public function set_rating_class($class = 'SimplePie_Rating')
f2f7b699 1008 {
a6e043ff 1009 return $this->registry->register('Rating', $class, true);
f2f7b699
AD
1010 }
1011
6d7d21a0 1012 /**
a6e043ff 1013 * Set which class SimplePie uses for `<media:restriction>`
6d7d21a0 1014 */
a6e043ff 1015 public function set_restriction_class($class = 'SimplePie_Restriction')
6d7d21a0 1016 {
a6e043ff 1017 return $this->registry->register('Restriction', $class, true);
6d7d21a0
AD
1018 }
1019
1020 /**
a6e043ff 1021 * Set which class SimplePie uses for content-type sniffing
6d7d21a0 1022 */
a6e043ff 1023 public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
6d7d21a0 1024 {
a6e043ff
AD
1025 return $this->registry->register('Content_Type_Sniffer', $class, true);
1026 }
1027
1028 /**
1029 * Set which class SimplePie uses item sources
1030 */
1031 public function set_source_class($class = 'SimplePie_Source')
1032 {
1033 return $this->registry->register('Source', $class, true);
6d7d21a0 1034 }
a6e043ff 1035 /**#@-*/
6d7d21a0 1036
f2f7b699 1037 /**
a6e043ff 1038 * Set the user agent string
f2f7b699 1039 *
f2f7b699
AD
1040 * @param string $ua New user agent string.
1041 */
a6e043ff 1042 public function set_useragent($ua = SIMPLEPIE_USERAGENT)
f2f7b699
AD
1043 {
1044 $this->useragent = (string) $ua;
1045 }
1046
1047 /**
1048 * Set callback function to create cache filename with
1049 *
f2f7b699
AD
1050 * @param mixed $function Callback function
1051 */
a6e043ff 1052 public function set_cache_name_function($function = 'md5')
f2f7b699
AD
1053 {
1054 if (is_callable($function))
1055 {
1056 $this->cache_name_function = $function;
1057 }
1058 }
1059
1060 /**
a6e043ff 1061 * Set options to make SP as fast as possible
f2f7b699 1062 *
a6e043ff
AD
1063 * Forgoes a substantial amount of data sanitization in favor of speed. This
1064 * turns SimplePie into a dumb parser of feeds.
f2f7b699 1065 *
f2f7b699
AD
1066 * @param bool $set Whether to set them or not
1067 */
a6e043ff 1068 public function set_stupidly_fast($set = false)
f2f7b699
AD
1069 {
1070 if ($set)
1071 {
1072 $this->enable_order_by_date(false);
1073 $this->remove_div(false);
1074 $this->strip_comments(false);
1075 $this->strip_htmltags(false);
1076 $this->strip_attributes(false);
1077 $this->set_image_handler(false);
1078 }
1079 }
1080
1081 /**
1082 * Set maximum number of feeds to check with autodiscovery
1083 *
f2f7b699
AD
1084 * @param int $max Maximum number of feeds to check
1085 */
a6e043ff 1086 public function set_max_checked_feeds($max = 10)
f2f7b699
AD
1087 {
1088 $this->max_checked_feeds = (int) $max;
1089 }
1090
a6e043ff 1091 public function remove_div($enable = true)
f2f7b699
AD
1092 {
1093 $this->sanitize->remove_div($enable);
1094 }
1095
a6e043ff 1096 public function strip_htmltags($tags = '', $encode = null)
f2f7b699
AD
1097 {
1098 if ($tags === '')
1099 {
1100 $tags = $this->strip_htmltags;
1101 }
1102 $this->sanitize->strip_htmltags($tags);
1103 if ($encode !== null)
1104 {
1105 $this->sanitize->encode_instead_of_strip($tags);
1106 }
1107 }
1108
a6e043ff 1109 public function encode_instead_of_strip($enable = true)
f2f7b699
AD
1110 {
1111 $this->sanitize->encode_instead_of_strip($enable);
1112 }
1113
a6e043ff 1114 public function strip_attributes($attribs = '')
f2f7b699
AD
1115 {
1116 if ($attribs === '')
1117 {
1118 $attribs = $this->strip_attributes;
1119 }
1120 $this->sanitize->strip_attributes($attribs);
1121 }
1122
a6e043ff
AD
1123 /**
1124 * Set the output encoding
1125 *
1126 * Allows you to override SimplePie's output to match that of your webpage.
1127 * This is useful for times when your webpages are not being served as
1128 * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
1129 * is similar to {@see set_input_encoding()}.
1130 *
1131 * It should be noted, however, that not all character encodings can support
1132 * all characters. If your page is being served as ISO-8859-1 and you try
1133 * to display a Japanese feed, you'll likely see garbled characters.
1134 * Because of this, it is highly recommended to ensure that your webpages
1135 * are served as UTF-8.
1136 *
1137 * The number of supported character encodings depends on whether your web
1138 * host supports {@link http://php.net/mbstring mbstring},
1139 * {@link http://php.net/iconv iconv}, or both. See
1140 * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
1141 * more information.
1142 *
1143 * @param string $encoding
1144 */
1145 public function set_output_encoding($encoding = 'UTF-8')
f2f7b699
AD
1146 {
1147 $this->sanitize->set_output_encoding($encoding);
1148 }
1149
a6e043ff 1150 public function strip_comments($strip = false)
f2f7b699
AD
1151 {
1152 $this->sanitize->strip_comments($strip);
1153 }
1154
1155 /**
1156 * Set element/attribute key/value pairs of HTML attributes
1157 * containing URLs that need to be resolved relative to the feed
1158 *
a6e043ff
AD
1159 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
1160 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
1161 * |q|@cite
1162 *
f2f7b699 1163 * @since 1.0
a6e043ff 1164 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
f2f7b699 1165 */
a6e043ff 1166 public function set_url_replacements($element_attribute = null)
f2f7b699
AD
1167 {
1168 $this->sanitize->set_url_replacements($element_attribute);
1169 }
1170
f2f7b699
AD
1171 /**
1172 * Set the handler to enable the display of cached images.
1173 *
f2f7b699
AD
1174 * @param str $page Web-accessible path to the handler_image.php file.
1175 * @param str $qs The query string that the value should be passed to.
1176 */
a6e043ff 1177 public function set_image_handler($page = false, $qs = 'i')
f2f7b699 1178 {
a5ae3915 1179 if ($page !== false)
f2f7b699
AD
1180 {
1181 $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1182 }
1183 else
1184 {
1185 $this->image_handler = '';
1186 }
1187 }
1188
6d7d21a0 1189 /**
a6e043ff 1190 * Set the limit for items returned per-feed with multifeeds
6d7d21a0 1191 *
6d7d21a0
AD
1192 * @param integer $limit The maximum number of items to return.
1193 */
a6e043ff 1194 public function set_item_limit($limit = 0)
6d7d21a0
AD
1195 {
1196 $this->item_limit = (int) $limit;
1197 }
1198
a6e043ff
AD
1199 /**
1200 * Initialize the feed object
1201 *
1202 * This is what makes everything happen. Period. This is where all of the
1203 * configuration options get processed, feeds are fetched, cached, and
1204 * parsed, and all of that other good stuff.
1205 *
1206 * @return boolean True if successful, false otherwise
1207 */
1208 public function init()
f2f7b699 1209 {
a5ae3915 1210 // Check absolute bare minimum requirements.
a6e043ff 1211 if (!extension_loaded('xml') || !extension_loaded('pcre'))
f2f7b699
AD
1212 {
1213 return false;
1214 }
a5ae3915
MK
1215 // Then check the xml extension is sane (i.e., libxml 2.7.x issue on PHP < 5.2.9 and libxml 2.7.0 to 2.7.2 on any version) if we don't have xmlreader.
1216 elseif (!extension_loaded('xmlreader'))
f2f7b699 1217 {
a5ae3915
MK
1218 static $xml_is_sane = null;
1219 if ($xml_is_sane === null)
f2f7b699 1220 {
a5ae3915
MK
1221 $parser_check = xml_parser_create();
1222 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1223 xml_parser_free($parser_check);
1224 $xml_is_sane = isset($values[0]['value']);
f2f7b699 1225 }
a5ae3915
MK
1226 if (!$xml_is_sane)
1227 {
1228 return false;
1229 }
1230 }
f2f7b699 1231
a6e043ff 1232 if (method_exists($this->sanitize, 'set_registry'))
a5ae3915 1233 {
a6e043ff 1234 $this->sanitize->set_registry($this->registry);
f2f7b699
AD
1235 }
1236
1237 // Pass whatever was set with config options over to the sanitizer.
a6e043ff
AD
1238 // Pass the classes in for legacy support; new classes should use the registry instead
1239 $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
1240 $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
f2f7b699 1241
a6e043ff 1242 if (!empty($this->multifeed_url))
f2f7b699 1243 {
a6e043ff
AD
1244 $i = 0;
1245 $success = 0;
f2f7b699 1246 $this->multifeed_objects = array();
a6e043ff
AD
1247 $this->error = array();
1248 foreach ($this->multifeed_url as $url)
f2f7b699 1249 {
a6e043ff
AD
1250 $this->multifeed_objects[$i] = clone $this;
1251 $this->multifeed_objects[$i]->set_feed_url($url);
1252 $single_success = $this->multifeed_objects[$i]->init();
1253 $success |= $single_success;
1254 if (!$single_success)
f2f7b699 1255 {
a6e043ff 1256 $this->error[$i] = $this->multifeed_objects[$i]->error();
f2f7b699 1257 }
a6e043ff
AD
1258 $i++;
1259 }
1260 return (bool) $success;
1261 }
1262 elseif ($this->feed_url === null && $this->raw_data === null)
1263 {
1264 return false;
1265 }
f2f7b699 1266
a6e043ff
AD
1267 $this->error = null;
1268 $this->data = array();
1269 $this->multifeed_objects = array();
1270 $cache = false;
1271
1272 if ($this->feed_url !== null)
1273 {
1274 $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
f2f7b699 1275
a6e043ff
AD
1276 // Decide whether to enable caching
1277 if ($this->cache && $parsed_feed_url['scheme'] !== '')
1278 {
1279 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
f2f7b699 1280 }
a6e043ff
AD
1281
1282 // Fetch the data via SimplePie_File into $this->raw_data
1283 if (($fetched = $this->fetch_data($cache)) === true)
f2f7b699 1284 {
a6e043ff 1285 return true;
f2f7b699 1286 }
a6e043ff
AD
1287 elseif ($fetched === false) {
1288 return false;
1289 }
1290
1291 list($headers, $sniffed) = $fetched;
1292 }
1293
1294 // Set up array of possible encodings
1295 $encodings = array();
1296
1297 // First check to see if input has been overridden.
1298 if ($this->input_encoding !== false)
1299 {
1300 $encodings[] = $this->input_encoding;
1301 }
f954bd49 1302
a6e043ff
AD
1303 $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1304 $text_types = array('text/xml', 'text/xml-external-parsed-entity');
f2f7b699 1305
a6e043ff
AD
1306 // RFC 3023 (only applies to sniffed content)
1307 if (isset($sniffed))
1308 {
1309 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1310 {
1311 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1312 {
1313 $encodings[] = strtoupper($charset[1]);
1314 }
1315 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1316 $encodings[] = 'UTF-8';
1317 }
1318 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1319 {
1320 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1321 {
1322 $encodings[] = $charset[1];
1323 }
1324 $encodings[] = 'US-ASCII';
1325 }
1326 // Text MIME-type default
1327 elseif (substr($sniffed, 0, 5) === 'text/')
f2f7b699 1328 {
a6e043ff 1329 $encodings[] = 'US-ASCII';
f2f7b699 1330 }
a6e043ff 1331 }
f954bd49 1332
a6e043ff
AD
1333 // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1334 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1335 $encodings[] = 'UTF-8';
1336 $encodings[] = 'ISO-8859-1';
f954bd49 1337
a6e043ff
AD
1338 // There's no point in trying an encoding twice
1339 $encodings = array_unique($encodings);
1340
1341 // Loop through each possible encoding, till we return something, or run out of possibilities
1342 foreach ($encodings as $encoding)
1343 {
1344 // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1345 if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
f2f7b699 1346 {
a6e043ff
AD
1347 // Create new parser
1348 $parser = $this->registry->create('Parser');
1349
1350 // If it's parsed fine
1351 if ($parser->parse($utf8_data, 'UTF-8'))
6d7d21a0 1352 {
a6e043ff
AD
1353 $this->data = $parser->get_data();
1354 if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
6d7d21a0 1355 {
a6e043ff
AD
1356 $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1357 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1358 return false;
6d7d21a0 1359 }
a6e043ff
AD
1360
1361 if (isset($headers))
6d7d21a0 1362 {
a6e043ff 1363 $this->data['headers'] = $headers;
6d7d21a0 1364 }
a6e043ff
AD
1365 $this->data['build'] = SIMPLEPIE_BUILD;
1366
1367 // Cache the file if caching is enabled
1368 if ($cache && !$cache->save($this))
1369 {
1370 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1371 }
1372 return true;
6d7d21a0 1373 }
f2f7b699 1374 }
a6e043ff 1375 }
f954bd49 1376
a6e043ff
AD
1377 if (isset($parser))
1378 {
1379 // We have an error, just set SimplePie_Misc::error to it and quit
1380 $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
1381 }
1382 else
1383 {
1384 $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.';
1385 }
f954bd49 1386
a6e043ff 1387 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
f954bd49 1388
a6e043ff
AD
1389 return false;
1390 }
f954bd49 1391
a6e043ff
AD
1392 /**
1393 * Fetch the data via SimplePie_File
1394 *
1395 * If the data is already cached, attempt to fetch it from there instead
1396 * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
1397 * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
1398 */
1399 protected function fetch_data(&$cache)
1400 {
1401 // If it's enabled, use the cache
1402 if ($cache)
1403 {
1404 // Load the Cache
1405 $this->data = $cache->load();
1406 if (!empty($this->data))
f2f7b699 1407 {
a6e043ff
AD
1408 // If the cache is for an outdated build of SimplePie
1409 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1410 {
1411 $cache->unlink();
1412 $this->data = array();
1413 }
1414 // If we've hit a collision just rerun it with caching disabled
1415 elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
f2f7b699 1416 {
a6e043ff
AD
1417 $cache = false;
1418 $this->data = array();
1419 }
1420 // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1421 elseif (isset($this->data['feed_url']))
1422 {
1423 // If the autodiscovery cache is still valid use it.
1424 if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1425 {
1426 // Do not need to do feed autodiscovery yet.
1427 if ($this->data['feed_url'] !== $this->data['url'])
1428 {
1429 $this->set_feed_url($this->data['feed_url']);
1430 return $this->init();
1431 }
f954bd49 1432
a6e043ff
AD
1433 $cache->unlink();
1434 $this->data = array();
1435 }
1436 }
1437 // Check if the cache has been updated
1438 elseif ($cache->mtime() + $this->cache_duration < time())
1439 {
1440 // If we have last-modified and/or etag set
1441 if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
f2f7b699 1442 {
a6e043ff
AD
1443 $headers = array(
1444 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1445 );
1446 if (isset($this->data['headers']['last-modified']))
6d7d21a0 1447 {
a6e043ff
AD
1448 $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1449 }
1450 if (isset($this->data['headers']['etag']))
1451 {
1452 $headers['if-none-match'] = $this->data['headers']['etag'];
1453 }
1454
1455 $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
f954bd49 1456
a6e043ff
AD
1457 if ($file->success)
1458 {
1459 if ($file->status_code === 304)
f954bd49 1460 {
a6e043ff
AD
1461 $cache->touch();
1462 return true;
f954bd49 1463 }
6d7d21a0 1464 }
f954bd49 1465 else
6d7d21a0 1466 {
a6e043ff 1467 unset($file);
6d7d21a0 1468 }
f2f7b699 1469 }
f2f7b699 1470 }
a6e043ff
AD
1471 // If the cache is still valid, just return true
1472 else
1473 {
1474 $this->raw_data = false;
1475 return true;
1476 }
1477 }
1478 // If the cache is empty, delete it
1479 else
1480 {
1481 $cache->unlink();
1482 $this->data = array();
f2f7b699 1483 }
a6e043ff
AD
1484 }
1485 // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
1486 if (!isset($file))
1487 {
1488 if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
a5ae3915 1489 {
a6e043ff 1490 $file =& $this->file;
a5ae3915
MK
1491 }
1492 else
1493 {
a6e043ff
AD
1494 $headers = array(
1495 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1496 );
1497 $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
a5ae3915 1498 }
f2f7b699 1499 }
a6e043ff
AD
1500 // If the file connection has an error, set SimplePie::error to that and quit
1501 if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
f2f7b699 1502 {
a6e043ff
AD
1503 $this->error = $file->error;
1504 return !empty($this->data);
1505 }
1506
1507 if (!$this->force_feed)
1508 {
1509 // Check if the supplied URL is a feed, if it isn't, look for it.
1510 $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
1511
1512 if (!$locate->is_feed($file))
f2f7b699 1513 {
a6e043ff
AD
1514 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1515 unset($file);
1516 try
f2f7b699 1517 {
a6e043ff
AD
1518 if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
1519 {
1520 $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed.";
1521 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1522 return false;
1523 }
f2f7b699 1524 }
a6e043ff
AD
1525 catch (SimplePie_Exception $e)
1526 {
1527 // This is usually because DOMDocument doesn't exist
1528 $this->error = $e->getMessage();
1529 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
1530 return false;
1531 }
1532 if ($cache)
f2f7b699 1533 {
a6e043ff
AD
1534 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1535 if (!$cache->save($this))
1536 {
1537 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1538 }
1539 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
f2f7b699 1540 }
a6e043ff 1541 $this->feed_url = $file->url;
f2f7b699 1542 }
a6e043ff 1543 $locate = null;
f2f7b699 1544 }
a6e043ff
AD
1545
1546 $this->raw_data = $file->body;
1547
1548 $headers = $file->headers;
1549 $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
1550 $sniffed = $sniffer->get_type();
1551
1552 return array($headers, $sniffed);
f2f7b699
AD
1553 }
1554
1555 /**
a6e043ff 1556 * Get the error message for the occured error
f2f7b699 1557 *
a6e043ff 1558 * @return string|array Error message, or array of messages for multifeeds
f2f7b699 1559 */
a6e043ff 1560 public function error()
f2f7b699
AD
1561 {
1562 return $this->error;
1563 }
1564
a6e043ff
AD
1565 /**
1566 * Get the raw XML
1567 *
1568 * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
1569 * the data instead of printing it.
1570 *
1571 * @return string|boolean Raw XML data, false if the cache is used
1572 */
1573 public function get_raw_data()
f2f7b699 1574 {
a6e043ff 1575 return $this->raw_data;
f2f7b699
AD
1576 }
1577
a6e043ff
AD
1578 /**
1579 * Get the character encoding used for output
1580 *
1581 * @since Preview Release
1582 * @return string
1583 */
1584 public function get_encoding()
1585 {
1586 return $this->sanitize->output_encoding;
1587 }
1588
1589 /**
1590 * Send the content-type header with correct encoding
1591 *
1592 * This method ensures that the SimplePie-enabled page is being served with
1593 * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
1594 * and character encoding HTTP headers (character encoding determined by the
1595 * {@see set_output_encoding} config option).
1596 *
1597 * This won't work properly if any content or whitespace has already been
1598 * sent to the browser, because it relies on PHP's
1599 * {@link http://php.net/header header()} function, and these are the
1600 * circumstances under which the function works.
1601 *
1602 * Because it's setting these settings for the entire page (as is the nature
1603 * of HTTP headers), this should only be used once per page (again, at the
1604 * top).
1605 *
1606 * @param string $mime MIME type to serve the page as
1607 */
1608 public function handle_content_type($mime = 'text/html')
f2f7b699
AD
1609 {
1610 if (!headers_sent())
1611 {
1612 $header = "Content-type: $mime;";
1613 if ($this->get_encoding())
1614 {
1615 $header .= ' charset=' . $this->get_encoding();
1616 }
1617 else
1618 {
1619 $header .= ' charset=UTF-8';
1620 }
1621 header($header);
1622 }
1623 }
1624
a6e043ff
AD
1625 /**
1626 * Get the type of the feed
1627 *
1628 * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
1629 * using {@link http://php.net/language.operators.bitwise bitwise operators}
1630 *
1631 * @since 0.8 (usage changed to using constants in 1.0)
1632 * @see SIMPLEPIE_TYPE_NONE Unknown.
1633 * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
1634 * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
1635 * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
1636 * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
1637 * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
1638 * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
1639 * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
1640 * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
1641 * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
1642 * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
1643 * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
1644 * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
1645 * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
1646 * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
1647 * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
1648 * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
1649 * @return int SIMPLEPIE_TYPE_* constant
1650 */
1651 public function get_type()
f2f7b699
AD
1652 {
1653 if (!isset($this->data['type']))
1654 {
1655 $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1656 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1657 {
1658 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1659 }
1660 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1661 {
1662 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1663 }
1664 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1665 {
1666 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1667 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1668 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1669 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1670 {
1671 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1672 }
1673 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1674 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1675 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1676 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1677 {
1678 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1679 }
1680 }
a5ae3915 1681 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
f2f7b699
AD
1682 {
1683 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
a5ae3915 1684 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
f2f7b699 1685 {
a5ae3915 1686 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
f2f7b699
AD
1687 {
1688 case '0.91':
1689 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
a5ae3915 1690 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
f2f7b699 1691 {
a5ae3915 1692 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
f2f7b699
AD
1693 {
1694 case '0':
1695 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1696 break;
1697
1698 case '24':
1699 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1700 break;
1701 }
1702 }
1703 break;
1704
1705 case '0.92':
1706 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1707 break;
1708
1709 case '0.93':
1710 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1711 break;
1712
1713 case '0.94':
1714 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1715 break;
1716
1717 case '2.0':
1718 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1719 break;
1720 }
1721 }
1722 }
1723 else
1724 {
1725 $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1726 }
1727 }
1728 return $this->data['type'];
1729 }
1730
1731 /**
a6e043ff 1732 * Get the URL for the feed
f2f7b699 1733 *
a6e043ff
AD
1734 * May or may not be different from the URL passed to {@see set_feed_url()},
1735 * depending on whether auto-discovery was used.
1736 *
1737 * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
f2f7b699
AD
1738 * @todo If we have a perm redirect we should return the new URL
1739 * @todo When we make the above change, let's support <itunes:new-feed-url> as well
1740 * @todo Also, |atom:link|@rel=self
a6e043ff 1741 * @return string|null
f2f7b699 1742 */
a6e043ff 1743 public function subscribe_url()
f2f7b699
AD
1744 {
1745 if ($this->feed_url !== null)
1746 {
1747 return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
1748 }
1749 else
1750 {
1751 return null;
1752 }
1753 }
1754
f2f7b699 1755 /**
a6e043ff 1756 * Get data for an feed-level element
f2f7b699 1757 *
a6e043ff
AD
1758 * This method allows you to get access to ANY element/attribute that is a
1759 * sub-element of the opening feed tag.
1760 *
1761 * The return value is an indexed array of elements matching the given
1762 * namespace and tag name. Each element has `attribs`, `data` and `child`
1763 * subkeys. For `attribs` and `child`, these contain namespace subkeys.
1764 * `attribs` then has one level of associative name => value data (where
1765 * `value` is a string) after the namespace. `child` has tag-indexed keys
1766 * after the namespace, each member of which is an indexed array matching
1767 * this same format.
1768 *
1769 * For example:
1770 * <pre>
1771 * // This is probably a bad example because we already support
1772 * // <media:content> natively, but it shows you how to parse through
1773 * // the nodes.
1774 * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
1775 * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
1776 * $file = $content[0]['attribs']['']['url'];
1777 * echo $file;
1778 * </pre>
1779 *
1780 * @since 1.0
1781 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1782 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1783 * @param string $tag Tag name
1784 * @return array
f2f7b699 1785 */
a6e043ff 1786 public function get_feed_tags($namespace, $tag)
f2f7b699
AD
1787 {
1788 $type = $this->get_type();
1789 if ($type & SIMPLEPIE_TYPE_ATOM_10)
1790 {
1791 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1792 {
1793 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1794 }
1795 }
1796 if ($type & SIMPLEPIE_TYPE_ATOM_03)
1797 {
1798 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1799 {
1800 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1801 }
1802 }
1803 if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1804 {
1805 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
1806 {
1807 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
1808 }
1809 }
1810 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1811 {
a5ae3915 1812 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
f2f7b699 1813 {
a5ae3915 1814 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
f2f7b699
AD
1815 }
1816 }
1817 return null;
1818 }
1819
a6e043ff
AD
1820 /**
1821 * Get data for an channel-level element
1822 *
1823 * This method allows you to get access to ANY element/attribute in the
1824 * channel/header section of the feed.
1825 *
1826 * See {@see SimplePie::get_feed_tags()} for a description of the return value
1827 *
1828 * @since 1.0
1829 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1830 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1831 * @param string $tag Tag name
1832 * @return array
1833 */
1834 public function get_channel_tags($namespace, $tag)
f2f7b699
AD
1835 {
1836 $type = $this->get_type();
1837 if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
1838 {
1839 if ($return = $this->get_feed_tags($namespace, $tag))
1840 {
1841 return $return;
1842 }
1843 }
1844 if ($type & SIMPLEPIE_TYPE_RSS_10)
1845 {
1846 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
1847 {
1848 if (isset($channel[0]['child'][$namespace][$tag]))
1849 {
1850 return $channel[0]['child'][$namespace][$tag];
1851 }
1852 }
1853 }
1854 if ($type & SIMPLEPIE_TYPE_RSS_090)
1855 {
1856 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
1857 {
1858 if (isset($channel[0]['child'][$namespace][$tag]))
1859 {
1860 return $channel[0]['child'][$namespace][$tag];
1861 }
1862 }
1863 }
1864 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1865 {
a5ae3915 1866 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
f2f7b699
AD
1867 {
1868 if (isset($channel[0]['child'][$namespace][$tag]))
1869 {
1870 return $channel[0]['child'][$namespace][$tag];
1871 }
1872 }
1873 }
1874 return null;
1875 }
1876
a6e043ff
AD
1877 /**
1878 * Get data for an channel-level element
1879 *
1880 * This method allows you to get access to ANY element/attribute in the
1881 * image/logo section of the feed.
1882 *
1883 * See {@see SimplePie::get_feed_tags()} for a description of the return value
1884 *
1885 * @since 1.0
1886 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1887 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1888 * @param string $tag Tag name
1889 * @return array
1890 */
1891 public function get_image_tags($namespace, $tag)
f2f7b699
AD
1892 {
1893 $type = $this->get_type();
1894 if ($type & SIMPLEPIE_TYPE_RSS_10)
1895 {
1896 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1897 {
1898 if (isset($image[0]['child'][$namespace][$tag]))
1899 {
1900 return $image[0]['child'][$namespace][$tag];
1901 }
1902 }
1903 }
1904 if ($type & SIMPLEPIE_TYPE_RSS_090)
1905 {
1906 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1907 {
1908 if (isset($image[0]['child'][$namespace][$tag]))
1909 {
1910 return $image[0]['child'][$namespace][$tag];
1911 }
1912 }
1913 }
1914 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1915 {
a5ae3915 1916 if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
f2f7b699
AD
1917 {
1918 if (isset($image[0]['child'][$namespace][$tag]))
1919 {
1920 return $image[0]['child'][$namespace][$tag];
1921 }
1922 }
1923 }
1924 return null;
1925 }
1926
a6e043ff
AD
1927 /**
1928 * Get the base URL value from the feed
1929 *
1930 * Uses `<xml:base>` if available, otherwise uses the first link in the
1931 * feed, or failing that, the URL of the feed itself.
1932 *
1933 * @see get_link
1934 * @see subscribe_url
1935 *
1936 * @param array $element
1937 * @return string
1938 */
1939 public function get_base($element = array())
f2f7b699
AD
1940 {
1941 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
1942 {
1943 return $element['xml_base'];
1944 }
1945 elseif ($this->get_link() !== null)
1946 {
1947 return $this->get_link();
1948 }
f2f7b699
AD
1949 else
1950 {
1951 return $this->subscribe_url();
1952 }
1953 }
1954
a6e043ff
AD
1955 /**
1956 * Sanitize feed data
1957 *
1958 * @access private
1959 * @see SimplePie_Sanitize::sanitize()
1960 * @param string $data Data to sanitize
1961 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
1962 * @param string $base Base URL to resolve URLs against
1963 * @return string Sanitized data
1964 */
1965 public function sanitize($data, $type, $base = '')
f2f7b699
AD
1966 {
1967 return $this->sanitize->sanitize($data, $type, $base);
1968 }
1969
a6e043ff
AD
1970 /**
1971 * Get the title of the feed
1972 *
1973 * Uses `<atom:title>`, `<title>` or `<dc:title>`
1974 *
1975 * @since 1.0 (previously called `get_feed_title` since 0.8)
1976 * @return string|null
1977 */
1978 public function get_title()
f2f7b699
AD
1979 {
1980 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
1981 {
a6e043ff 1982 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
f2f7b699
AD
1983 }
1984 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
1985 {
a6e043ff 1986 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
f2f7b699
AD
1987 }
1988 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1989 {
1990 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1991 }
1992 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1993 {
1994 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1995 }
a5ae3915 1996 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
f2f7b699
AD
1997 {
1998 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1999 }
2000 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2001 {
2002 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2003 }
2004 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2005 {
2006 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2007 }
2008 else
2009 {
2010 return null;
2011 }
2012 }
2013
a6e043ff
AD
2014 /**
2015 * Get a category for the feed
2016 *
2017 * @since Unknown
2018 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
2019 * @return SimplePie_Category|null
2020 */
2021 public function get_category($key = 0)
f2f7b699 2022 {
6d7d21a0
AD
2023 $categories = $this->get_categories();
2024 if (isset($categories[$key]))
f2f7b699 2025 {
6d7d21a0 2026 return $categories[$key];
f2f7b699
AD
2027 }
2028 else
2029 {
2030 return null;
2031 }
2032 }
2033
a6e043ff
AD
2034 /**
2035 * Get all categories for the feed
2036 *
2037 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
2038 *
2039 * @since Unknown
2040 * @return array|null List of {@see SimplePie_Category} objects
2041 */
2042 public function get_categories()
f2f7b699 2043 {
6d7d21a0 2044 $categories = array();
f2f7b699 2045
6d7d21a0 2046 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
f2f7b699 2047 {
6d7d21a0
AD
2048 $term = null;
2049 $scheme = null;
2050 $label = null;
2051 if (isset($category['attribs']['']['term']))
f2f7b699 2052 {
6d7d21a0 2053 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 2054 }
6d7d21a0 2055 if (isset($category['attribs']['']['scheme']))
f2f7b699 2056 {
6d7d21a0 2057 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 2058 }
6d7d21a0 2059 if (isset($category['attribs']['']['label']))
f2f7b699 2060 {
6d7d21a0 2061 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 2062 }
a6e043ff 2063 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
f2f7b699 2064 }
a5ae3915 2065 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
f2f7b699 2066 {
a5ae3915
MK
2067 // This is really the label, but keep this as the term also for BC.
2068 // Label will also work on retrieving because that falls back to term.
2069 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2070 if (isset($category['attribs']['']['domain']))
2071 {
2072 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2073 }
2074 else
2075 {
2076 $scheme = null;
2077 }
a6e043ff 2078 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
f2f7b699 2079 }
6d7d21a0 2080 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
f2f7b699 2081 {
a6e043ff 2082 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
6d7d21a0
AD
2083 }
2084 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2085 {
a6e043ff 2086 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
6d7d21a0
AD
2087 }
2088
2089 if (!empty($categories))
2090 {
a6e043ff 2091 return array_unique($categories);
6d7d21a0
AD
2092 }
2093 else
2094 {
2095 return null;
2096 }
2097 }
2098
a6e043ff
AD
2099 /**
2100 * Get an author for the feed
2101 *
2102 * @since 1.1
2103 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
2104 * @return SimplePie_Author|null
2105 */
2106 public function get_author($key = 0)
6d7d21a0
AD
2107 {
2108 $authors = $this->get_authors();
2109 if (isset($authors[$key]))
2110 {
2111 return $authors[$key];
2112 }
2113 else
2114 {
2115 return null;
2116 }
2117 }
2118
a6e043ff
AD
2119 /**
2120 * Get all authors for the feed
2121 *
2122 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
2123 *
2124 * @since 1.1
2125 * @return array|null List of {@see SimplePie_Author} objects
2126 */
2127 public function get_authors()
6d7d21a0
AD
2128 {
2129 $authors = array();
2130 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2131 {
2132 $name = null;
2133 $uri = null;
2134 $email = null;
2135 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2136 {
2137 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2138 }
2139 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2140 {
2141 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
2142 }
2143 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2144 {
2145 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2146 }
2147 if ($name !== null || $email !== null || $uri !== null)
2148 {
a6e043ff 2149 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
6d7d21a0
AD
2150 }
2151 }
2152 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2153 {
2154 $name = null;
2155 $url = null;
2156 $email = null;
2157 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2158 {
2159 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2160 }
2161 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2162 {
2163 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
2164 }
2165 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2166 {
2167 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2168 }
2169 if ($name !== null || $email !== null || $url !== null)
2170 {
a6e043ff 2171 $authors[] = $this->registry->create('Author', array($name, $url, $email));
6d7d21a0
AD
2172 }
2173 }
2174 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2175 {
a6e043ff 2176 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
6d7d21a0
AD
2177 }
2178 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2179 {
a6e043ff 2180 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
6d7d21a0
AD
2181 }
2182 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2183 {
a6e043ff 2184 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
6d7d21a0
AD
2185 }
2186
2187 if (!empty($authors))
2188 {
a6e043ff 2189 return array_unique($authors);
6d7d21a0
AD
2190 }
2191 else
2192 {
2193 return null;
2194 }
2195 }
2196
a6e043ff
AD
2197 /**
2198 * Get a contributor for the feed
2199 *
2200 * @since 1.1
2201 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
2202 * @return SimplePie_Author|null
2203 */
2204 public function get_contributor($key = 0)
6d7d21a0
AD
2205 {
2206 $contributors = $this->get_contributors();
2207 if (isset($contributors[$key]))
2208 {
2209 return $contributors[$key];
2210 }
2211 else
2212 {
2213 return null;
2214 }
2215 }
2216
a6e043ff
AD
2217 /**
2218 * Get all contributors for the feed
2219 *
2220 * Uses `<atom:contributor>`
2221 *
2222 * @since 1.1
2223 * @return array|null List of {@see SimplePie_Author} objects
2224 */
2225 public function get_contributors()
6d7d21a0
AD
2226 {
2227 $contributors = array();
2228 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2229 {
2230 $name = null;
2231 $uri = null;
2232 $email = null;
2233 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2234 {
2235 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2236 }
2237 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2238 {
2239 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
2240 }
2241 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2242 {
2243 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2244 }
2245 if ($name !== null || $email !== null || $uri !== null)
2246 {
a6e043ff 2247 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
6d7d21a0
AD
2248 }
2249 }
2250 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2251 {
2252 $name = null;
2253 $url = null;
2254 $email = null;
2255 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2256 {
2257 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2258 }
2259 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2260 {
2261 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
2262 }
2263 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2264 {
2265 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2266 }
2267 if ($name !== null || $email !== null || $url !== null)
2268 {
a6e043ff 2269 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
6d7d21a0
AD
2270 }
2271 }
2272
2273 if (!empty($contributors))
2274 {
a6e043ff 2275 return array_unique($contributors);
6d7d21a0
AD
2276 }
2277 else
2278 {
2279 return null;
2280 }
2281 }
2282
a6e043ff
AD
2283 /**
2284 * Get a single link for the feed
2285 *
2286 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2287 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
2288 * @param string $rel The relationship of the link to return
2289 * @return string|null Link URL
2290 */
2291 public function get_link($key = 0, $rel = 'alternate')
6d7d21a0
AD
2292 {
2293 $links = $this->get_links($rel);
2294 if (isset($links[$key]))
2295 {
2296 return $links[$key];
2297 }
2298 else
2299 {
2300 return null;
2301 }
2302 }
2303
2304 /**
a6e043ff
AD
2305 * Get the permalink for the item
2306 *
2307 * Returns the first link available with a relationship of "alternate".
2308 * Identical to {@see get_link()} with key 0
2309 *
2310 * @see get_link
2311 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2312 * @internal Added for parity between the parent-level and the item/entry-level.
2313 * @return string|null Link URL
6d7d21a0 2314 */
a6e043ff 2315 public function get_permalink()
6d7d21a0
AD
2316 {
2317 return $this->get_link(0);
2318 }
2319
a6e043ff
AD
2320 /**
2321 * Get all links for the feed
2322 *
2323 * Uses `<atom:link>` or `<link>`
2324 *
2325 * @since Beta 2
2326 * @param string $rel The relationship of links to return
2327 * @return array|null Links found for the feed (strings)
2328 */
2329 public function get_links($rel = 'alternate')
6d7d21a0
AD
2330 {
2331 if (!isset($this->data['links']))
2332 {
2333 $this->data['links'] = array();
2334 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2335 {
2336 foreach ($links as $link)
2337 {
2338 if (isset($link['attribs']['']['href']))
2339 {
2340 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2341 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2342 }
2343 }
2344 }
2345 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2346 {
2347 foreach ($links as $link)
2348 {
2349 if (isset($link['attribs']['']['href']))
2350 {
2351 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2352 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2353
2354 }
2355 }
2356 }
2357 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2358 {
2359 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2360 }
2361 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2362 {
2363 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2364 }
a5ae3915 2365 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
6d7d21a0
AD
2366 {
2367 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2368 }
2369
2370 $keys = array_keys($this->data['links']);
2371 foreach ($keys as $key)
2372 {
a6e043ff 2373 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
6d7d21a0
AD
2374 {
2375 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2376 {
2377 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2378 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2379 }
2380 else
2381 {
2382 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2383 }
2384 }
a5ae3915 2385 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
6d7d21a0
AD
2386 {
2387 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2388 }
2389 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2390 }
2391 }
2392
2393 if (isset($this->data['links'][$rel]))
2394 {
2395 return $this->data['links'][$rel];
2396 }
2397 else
2398 {
2399 return null;
f2f7b699
AD
2400 }
2401 }
2402
a6e043ff 2403 public function get_all_discovered_feeds()
a5ae3915
MK
2404 {
2405 return $this->all_discovered_feeds;
2406 }
2407
a6e043ff
AD
2408 /**
2409 * Get the content for the item
2410 *
2411 * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
2412 * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
2413 *
2414 * @since 1.0 (previously called `get_feed_description()` since 0.8)
2415 * @return string|null
2416 */
2417 public function get_description()
f2f7b699
AD
2418 {
2419 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2420 {
a6e043ff 2421 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
f2f7b699
AD
2422 }
2423 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2424 {
a6e043ff 2425 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
f2f7b699
AD
2426 }
2427 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2428 {
2429 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2430 }
2431 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2432 {
2433 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2434 }
a5ae3915 2435 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
f2f7b699 2436 {
a5ae3915 2437 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
f2f7b699
AD
2438 }
2439 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2440 {
2441 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2442 }
2443 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2444 {
2445 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2446 }
2447 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2448 {
2449 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2450 }
2451 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2452 {
2453 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2454 }
2455 else
2456 {
2457 return null;
2458 }
2459 }
2460
a6e043ff
AD
2461 /**
2462 * Get the copyright info for the feed
2463 *
2464 * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
2465 *
2466 * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
2467 * @return string|null
2468 */
2469 public function get_copyright()
f2f7b699
AD
2470 {
2471 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2472 {
a6e043ff 2473 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
f2f7b699 2474 }
6d7d21a0
AD
2475 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2476 {
a6e043ff 2477 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
6d7d21a0 2478 }
a5ae3915 2479 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
f2f7b699
AD
2480 {
2481 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2482 }
2483 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2484 {
2485 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2486 }
2487 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2488 {
2489 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2490 }
2491 else
2492 {
2493 return null;
2494 }
2495 }
2496
a6e043ff
AD
2497 /**
2498 * Get the language for the feed
2499 *
2500 * Uses `<language>`, `<dc:language>`, or @xml_lang
2501 *
2502 * @since 1.0 (previously called `get_feed_language()` since 0.8)
2503 * @return string|null
2504 */
2505 public function get_language()
f2f7b699 2506 {
a5ae3915 2507 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
f2f7b699
AD
2508 {
2509 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2510 }
2511 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2512 {
2513 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2514 }
2515 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2516 {
2517 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2518 }
2519 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2520 {
2521 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2522 }
2523 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2524 {
2525 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2526 }
2527 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2528 {
2529 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2530 }
2531 elseif (isset($this->data['headers']['content-language']))
2532 {
2533 return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2534 }
2535 else
2536 {
2537 return null;
2538 }
2539 }
2540
a6e043ff
AD
2541 /**
2542 * Get the latitude coordinates for the item
2543 *
2544 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2545 *
2546 * Uses `<geo:lat>` or `<georss:point>`
2547 *
2548 * @since 1.0
2549 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2550 * @link http://www.georss.org/ GeoRSS
2551 * @return string|null
2552 */
2553 public function get_latitude()
f2f7b699 2554 {
a6e043ff 2555
f2f7b699
AD
2556 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2557 {
2558 return (float) $return[0]['data'];
2559 }
5b085627 2560 elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
f2f7b699
AD
2561 {
2562 return (float) $match[1];
2563 }
2564 else
2565 {
2566 return null;
2567 }
2568 }
2569
a6e043ff
AD
2570 /**
2571 * Get the longitude coordinates for the feed
2572 *
2573 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2574 *
2575 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2576 *
2577 * @since 1.0
2578 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2579 * @link http://www.georss.org/ GeoRSS
2580 * @return string|null
2581 */
2582 public function get_longitude()
f2f7b699
AD
2583 {
2584 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2585 {
2586 return (float) $return[0]['data'];
2587 }
2588 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2589 {
2590 return (float) $return[0]['data'];
2591 }
5b085627 2592 elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
f2f7b699
AD
2593 {
2594 return (float) $match[2];
2595 }
2596 else
2597 {
2598 return null;
2599 }
2600 }
2601
a6e043ff
AD
2602 /**
2603 * Get the feed logo's title
2604 *
2605 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
2606 *
2607 * Uses `<image><title>` or `<image><dc:title>`
2608 *
2609 * @return string|null
2610 */
2611 public function get_image_title()
f2f7b699
AD
2612 {
2613 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2614 {
2615 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2616 }
2617 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2618 {
2619 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2620 }
a5ae3915 2621 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
f2f7b699
AD
2622 {
2623 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2624 }
2625 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2626 {
2627 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2628 }
2629 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2630 {
2631 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2632 }
2633 else
2634 {
2635 return null;
2636 }
2637 }
2638
a6e043ff
AD
2639 /**
2640 * Get the feed logo's URL
2641 *
2642 * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
2643 * have a "feed logo" URL. This points directly to the image itself.
2644 *
2645 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2646 * `<image><title>` or `<image><dc:title>`
2647 *
2648 * @return string|null
2649 */
2650 public function get_image_url()
f2f7b699
AD
2651 {
2652 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2653 {
2654 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2655 }
2656 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2657 {
2658 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2659 }
2660 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2661 {
2662 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2663 }
2664 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2665 {
2666 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2667 }
2668 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2669 {
2670 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2671 }
a5ae3915 2672 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
f2f7b699
AD
2673 {
2674 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2675 }
2676 else
2677 {
2678 return null;
2679 }
2680 }
2681
a6e043ff
AD
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 {
f2f7b699
AD
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 }
a5ae3915 2703 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
f2f7b699
AD
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
a6e043ff
AD
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()
f2f7b699 2724 {
a5ae3915 2725 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
f2f7b699
AD
2726 {
2727 return round($return[0]['data']);
2728 }
a5ae3915 2729 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
f2f7b699
AD
2730 {
2731 return 88.0;
2732 }
2733 else
2734 {
2735 return null;
2736 }
2737 }
2738
a6e043ff
AD
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()
f2f7b699 2750 {
a5ae3915 2751 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
f2f7b699
AD
2752 {
2753 return round($return[0]['data']);
2754 }
a5ae3915 2755 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
f2f7b699
AD
2756 {
2757 return 31.0;
2758 }
2759 else
2760 {
2761 return null;
2762 }
2763 }
2764
a6e043ff
AD
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)
f2f7b699 2775 {
a5ae3915 2776 $max = (int) $max;
f2f7b699 2777 $qty = count($this->get_items());
a5ae3915 2778 if ($max === 0)
f2f7b699
AD
2779 {
2780 return $qty;
2781 }
2782 else
2783 {
2784 return ($qty > $max) ? $max : $qty;
2785 }
2786 }
2787
a6e043ff
AD
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)
f2f7b699
AD
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
a6e043ff
AD
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)
f2f7b699 2827 {
a5ae3915 2828 if (!isset($this->data['items']))
f2f7b699 2829 {
a5ae3915 2830 if (!empty($this->multifeed_objects))
f2f7b699 2831 {
a5ae3915 2832 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
f2f7b699 2833 }
a5ae3915 2834 else
f2f7b699 2835 {
a5ae3915
MK
2836 $this->data['items'] = array();
2837 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
f2f7b699 2838 {
a5ae3915
MK
2839 $keys = array_keys($items);
2840 foreach ($keys as $key)
2841 {
a6e043ff 2842 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
a5ae3915 2843 }
f2f7b699 2844 }
a5ae3915 2845 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
f2f7b699 2846 {
a5ae3915
MK
2847 $keys = array_keys($items);
2848 foreach ($keys as $key)
2849 {
a6e043ff 2850 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
a5ae3915 2851 }
f2f7b699 2852 }
a5ae3915 2853 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
f2f7b699 2854 {
a5ae3915
MK
2855 $keys = array_keys($items);
2856 foreach ($keys as $key)
2857 {
a6e043ff 2858 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
a5ae3915 2859 }
f2f7b699 2860 }
a5ae3915
MK
2861 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2862 {
2863 $keys = array_keys($items);
2864 foreach ($keys as $key)
2865 {
a6e043ff 2866 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
a5ae3915
MK
2867 }
2868 }
2869 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
f2f7b699 2870 {
a5ae3915
MK
2871 $keys = array_keys($items);
2872 foreach ($keys as $key)
2873 {
a6e043ff 2874 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
a5ae3915 2875 }
f2f7b699
AD
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
a5ae3915 2883 if ($this->order_by_date && empty($this->multifeed_objects))
f2f7b699
AD
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 {
a6e043ff 2900 usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
f2f7b699
AD
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
a5ae3915 2911 if ($end === 0)
f2f7b699
AD
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
a5ae3915 2926 /**
a6e043ff
AD
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
a5ae3915 2992 */
a6e043ff 2993 public static function sort_items($a, $b)
f2f7b699
AD
2994 {
2995 return $a->get_date('U') <= $b->get_date('U');
2996 }
2997
a5ae3915 2998 /**
a6e043ff
AD
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
a5ae3915 3010 */
a6e043ff 3011 public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
f2f7b699
AD
3012 {
3013 if (is_array($urls) && sizeof($urls) > 0)
3014 {
3015 $items = array();
3016 foreach ($urls as $arg)
3017 {
a6e043ff 3018 if ($arg instanceof SimplePie)
f2f7b699 3019 {
6d7d21a0 3020 $items = array_merge($items, $arg->get_items(0, $limit));
f2f7b699
AD
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 {
a6e043ff 3040 usort($items, array(get_class($urls[0]), 'sort_items'));
f2f7b699
AD
3041 }
3042
a5ae3915 3043 if ($end === 0)
f2f7b699
AD
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}
3059
a6e043ff
AD
3060/**
3061 * Manages all author-related data
3062 *
3063 * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
3064 *
3065 * This class can be overloaded with {@see SimplePie::set_author_class()}
3066 *
3067 * @package SimplePie
3068 * @subpackage API
3069 */
3070class SimplePie_Author
f2f7b699 3071{
a6e043ff
AD
3072 /**
3073 * Author's name
3074 *
3075 * @var string
3076 * @see get_name()
3077 */
3078 var $name;
3079
3080 /**
3081 * Author's link
3082 *
3083 * @var string
3084 * @see get_link()
3085 */
3086 var $link;
3087
3088 /**
3089 * Author's email address
3090 *
3091 * @var string
3092 * @see get_email()
3093 */
3094 var $email;
f2f7b699 3095
a6e043ff
AD
3096 /**
3097 * Constructor, used to input the data
3098 *
3099 * @param string $name
3100 * @param string $link
3101 * @param string $email
3102 */
3103 public function __construct($name = null, $link = null, $email = null)
f2f7b699 3104 {
a6e043ff
AD
3105 $this->name = $name;
3106 $this->link = $link;
3107 $this->email = $email;
f2f7b699
AD
3108 }
3109
a6e043ff
AD
3110 /**
3111 * String-ified version
3112 *
3113 * @return string
3114 */
3115 public function __toString()
f2f7b699 3116 {
a6e043ff
AD
3117 // There is no $this->data here
3118 return md5(serialize($this));
f2f7b699 3119 }
f954bd49 3120
6d7d21a0 3121 /**
a6e043ff
AD
3122 * Author's name
3123 *
3124 * @return string|null
6d7d21a0 3125 */
a6e043ff 3126 public function get_name()
6d7d21a0 3127 {
a6e043ff 3128 if ($this->name !== null)
a5ae3915 3129 {
a6e043ff
AD
3130 return $this->name;
3131 }
3132 else
3133 {
3134 return null;
a5ae3915 3135 }
6d7d21a0 3136 }
f2f7b699 3137
a6e043ff
AD
3138 /**
3139 * Author's link
3140 *
3141 * @return string|null
3142 */
3143 public function get_link()
f2f7b699 3144 {
a6e043ff 3145 if ($this->link !== null)
f2f7b699 3146 {
a6e043ff 3147 return $this->link;
f2f7b699
AD
3148 }
3149 else
3150 {
3151 return null;
3152 }
3153 }
3154
a6e043ff
AD
3155 /**
3156 * Author's email address
3157 *
3158 * @return string|null
3159 */
3160 public function get_email()
f2f7b699 3161 {
a6e043ff
AD
3162 if ($this->email !== null)
3163 {
3164 return $this->email;
3165 }
3166 else
3167 {
3168 return null;
3169 }
f2f7b699 3170 }
a6e043ff 3171}
f2f7b699 3172
a6e043ff
AD
3173/**
3174 * Base for cache objects
3175 *
3176 * Classes to be used with {@see SimplePie_Cache::register()} are expected
3177 * to implement this interface.
3178 *
3179 * @package SimplePie
3180 * @subpackage Caching
3181 */
3182interface SimplePie_Cache_Base
3183{
3184 /**
3185 * Feed cache type
3186 *
3187 * @var string
3188 */
3189 const TYPE_FEED = 'spc';
f2f7b699 3190
a6e043ff
AD
3191 /**
3192 * Image cache type
3193 *
3194 * @var string
3195 */
3196 const TYPE_IMAGE = 'spi';
f2f7b699 3197
a6e043ff
AD
3198 /**
3199 * Create a new cache object
3200 *
3201 * @param string $location Location string (from SimplePie::$cache_location)
3202 * @param string $name Unique ID for the cache
3203 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3204 */
3205 public function __construct($location, $name, $type);
3206
3207 /**
3208 * Save data to the cache
3209 *
3210 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3211 * @return bool Successfulness
3212 */
3213 public function save($data);
3214
3215 /**
3216 * Retrieve the data saved to the cache
3217 *
3218 * @return array Data for SimplePie::$data
3219 */
3220 public function load();
3221
3222 /**
3223 * Retrieve the last modified time for the cache
3224 *
3225 * @return int Timestamp
3226 */
3227 public function mtime();
3228
3229 /**
3230 * Set the last modified time to the current time
3231 *
3232 * @return bool Success status
3233 */
3234 public function touch();
3235
3236 /**
3237 * Remove the cache
3238 *
3239 * @return bool Success status
3240 */
3241 public function unlink();
3242}
3243
3244/**
3245 * Base class for database-based caches
3246 *
3247 * @package SimplePie
3248 * @subpackage Caching
3249 */
3250abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
3251{
3252 /**
3253 * Helper for database conversion
3254 *
3255 * Converts a given {@see SimplePie} object into data to be stored
3256 *
3257 * @param SimplePie $data
3258 * @return array First item is the serialized data for storage, second item is the unique ID for this item
3259 */
3260 protected static function prepare_simplepie_object_for_cache($data)
f2f7b699 3261 {
a6e043ff
AD
3262 $items = $data->get_items();
3263 $items_by_id = array();
3264
3265 if (!empty($items))
f2f7b699 3266 {
a6e043ff 3267 foreach ($items as $item)
6d7d21a0 3268 {
a6e043ff 3269 $items_by_id[$item->get_id()] = $item;
6d7d21a0 3270 }
a6e043ff
AD
3271
3272 if (count($items_by_id) !== count($items))
6d7d21a0 3273 {
a6e043ff
AD
3274 $items_by_id = array();
3275 foreach ($items as $item)
3276 {
3277 $items_by_id[$item->get_id(true)] = $item;
3278 }
6d7d21a0 3279 }
a6e043ff
AD
3280
3281 if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
6d7d21a0 3282 {
a6e043ff 3283 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
6d7d21a0 3284 }
a6e043ff 3285 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
6d7d21a0 3286 {
a6e043ff 3287 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
6d7d21a0 3288 }
a6e043ff 3289 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
6d7d21a0 3290 {
a6e043ff 3291 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
6d7d21a0 3292 }
a6e043ff 3293 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
6d7d21a0 3294 {
a6e043ff 3295 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
6d7d21a0 3296 }
a6e043ff 3297 else
6d7d21a0 3298 {
a6e043ff 3299 $channel = null;
6d7d21a0 3300 }
6d7d21a0 3301
a6e043ff 3302 if ($channel !== null)
6d7d21a0 3303 {
a6e043ff
AD
3304 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
3305 {
3306 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
3307 }
3308 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
3309 {
3310 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
3311 }
3312 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
3313 {
3314 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
3315 }
3316 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
3317 {
3318 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
3319 }
3320 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
3321 {
3322 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
3323 }
6d7d21a0 3324 }
a6e043ff 3325 if (isset($data->data['items']))
6d7d21a0 3326 {
a6e043ff 3327 unset($data->data['items']);
6d7d21a0 3328 }
a6e043ff 3329 if (isset($data->data['ordered_items']))
6d7d21a0 3330 {
a6e043ff 3331 unset($data->data['ordered_items']);
6d7d21a0 3332 }
f2f7b699 3333 }
a6e043ff
AD
3334 return array(serialize($data->data), $items_by_id);
3335 }
3336}
3337
3338/**
3339 * Caches data to the filesystem
3340 *
3341 * @package SimplePie
3342 * @subpackage Caching
3343 */
3344class SimplePie_Cache_File implements SimplePie_Cache_Base
3345{
3346 /**
3347 * Location string
3348 *
3349 * @see SimplePie::$cache_location
3350 * @var string
3351 */
3352 protected $location;
3353
3354 /**
3355 * Filename
3356 *
3357 * @var string
3358 */
3359 protected $filename;
3360
3361 /**
3362 * File extension
3363 *
3364 * @var string
3365 */
3366 protected $extension;
3367
3368 /**
3369 * File path
3370 *
3371 * @var string
3372 */
3373 protected $name;
3374
3375 /**
3376 * Create a new cache object
3377 *
3378 * @param string $location Location string (from SimplePie::$cache_location)
3379 * @param string $name Unique ID for the cache
3380 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3381 */
3382 public function __construct($location, $name, $type)
3383 {
3384 $this->location = $location;
3385 $this->filename = $name;
3386 $this->extension = $type;
3387 $this->name = "$this->location/$this->filename.$this->extension";
f2f7b699
AD
3388 }
3389
a6e043ff
AD
3390 /**
3391 * Save data to the cache
3392 *
3393 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3394 * @return bool Successfulness
3395 */
3396 public function save($data)
f2f7b699 3397 {
a6e043ff 3398 if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
f2f7b699 3399 {
a6e043ff
AD
3400 if ($data instanceof SimplePie)
3401 {
3402 $data = $data->data;
3403 }
3404
3405 $data = serialize($data);
3406 return (bool) file_put_contents($this->name, $data);
f2f7b699 3407 }
a6e043ff
AD
3408 return false;
3409 }
3410
3411 /**
3412 * Retrieve the data saved to the cache
3413 *
3414 * @return array Data for SimplePie::$data
3415 */
3416 public function load()
3417 {
3418 if (file_exists($this->name) && is_readable($this->name))
f2f7b699 3419 {
a6e043ff 3420 return unserialize(file_get_contents($this->name));
f2f7b699 3421 }
a6e043ff
AD
3422 return false;
3423 }
3424
3425 /**
3426 * Retrieve the last modified time for the cache
3427 *
3428 * @return int Timestamp
3429 */
3430 public function mtime()
3431 {
3432 if (file_exists($this->name))
f2f7b699 3433 {
a6e043ff 3434 return filemtime($this->name);
f2f7b699 3435 }
a6e043ff
AD
3436 return false;
3437 }
3438
3439 /**
3440 * Set the last modified time to the current time
3441 *
3442 * @return bool Success status
3443 */
3444 public function touch()
3445 {
3446 if (file_exists($this->name))
f2f7b699 3447 {
a6e043ff 3448 return touch($this->name);
f2f7b699 3449 }
a6e043ff
AD
3450 return false;
3451 }
3452
3453 /**
3454 * Remove the cache
3455 *
3456 * @return bool Success status
3457 */
3458 public function unlink()
3459 {
3460 if (file_exists($this->name))
f2f7b699 3461 {
a6e043ff 3462 return unlink($this->name);
f2f7b699 3463 }
a6e043ff
AD
3464 return false;
3465 }
3466}
3467
3468/**
3469 * Caches data to memcache
3470 *
3471 * Registered for URLs with the "memcache" protocol
3472 *
3473 * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
3474 * connect to memcache on `localhost` on port 11211. All tables will be
3475 * prefixed with `sp_` and data will expire after 3600 seconds
3476 *
3477 * @package SimplePie
3478 * @subpackage Caching
3479 * @uses Memcache
3480 */
3481class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
3482{
3483 /**
3484 * Memcache instance
3485 *
3486 * @var Memcache
3487 */
3488 protected $cache;
3489
3490 /**
3491 * Options
3492 *
3493 * @var array
3494 */
3495 protected $options;
3496
3497 /**
3498 * Cache name
3499 *
3500 * @var string
3501 */
3502 protected $name;
3503
3504 /**
3505 * Create a new cache object
3506 *
3507 * @param string $location Location string (from SimplePie::$cache_location)
3508 * @param string $name Unique ID for the cache
3509 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3510 */
3511 public function __construct($location, $name, $type)
3512 {
3513 $this->options = array(
3514 'host' => '127.0.0.1',
3515 'port' => 11211,
3516 'extras' => array(
3517 'timeout' => 3600, // one hour
3518 'prefix' => 'simplepie_',
3519 ),
3520 );
3521 $parsed = SimplePie_Cache::parse_URL($location);
3522 $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
3523 $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
3524 $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
3525 $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
3526
3527 $this->cache = new Memcache();
3528 $this->cache->addServer($this->options['host'], (int) $this->options['port']);
3529 }
3530
3531 /**
3532 * Save data to the cache
3533 *
3534 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3535 * @return bool Successfulness
3536 */
3537 public function save($data)
3538 {
3539 if ($data instanceof SimplePie)
5b085627 3540 {
a6e043ff 3541 $data = $data->data;
5b085627 3542 }
a6e043ff
AD
3543 return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
3544 }
5b085627 3545
a6e043ff
AD
3546 /**
3547 * Retrieve the data saved to the cache
3548 *
3549 * @return array Data for SimplePie::$data
3550 */
3551 public function load()
3552 {
3553 $data = $this->cache->get($this->name);
3554
3555 if ($data !== false)
f2f7b699 3556 {
a6e043ff 3557 return unserialize($data);
f2f7b699 3558 }
a6e043ff
AD
3559 return false;
3560 }
3561
3562 /**
3563 * Retrieve the last modified time for the cache
3564 *
3565 * @return int Timestamp
3566 */
3567 public function mtime()
3568 {
3569 $data = $this->cache->get($this->name);
3570
3571 if ($data !== false)
f2f7b699 3572 {
a6e043ff
AD
3573 // essentially ignore the mtime because Memcache expires on it's own
3574 return time();
f2f7b699 3575 }
a6e043ff
AD
3576
3577 return false;
f2f7b699
AD
3578 }
3579
a6e043ff
AD
3580 /**
3581 * Set the last modified time to the current time
3582 *
3583 * @return bool Success status
3584 */
3585 public function touch()
f2f7b699 3586 {
a6e043ff
AD
3587 $data = $this->cache->get($this->name);
3588
3589 if ($data !== false)
f2f7b699 3590 {
a6e043ff 3591 return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
f2f7b699 3592 }
a6e043ff
AD
3593
3594 return false;
3595 }
3596
3597 /**
3598 * Remove the cache
3599 *
3600 * @return bool Success status
3601 */
3602 public function unlink()
3603 {
3604 return $this->cache->delete($this->name, 0);
3605 }
3606}
3607
3608/**
3609 * Caches data to a MySQL database
3610 *
3611 * Registered for URLs with the "mysql" protocol
3612 *
3613 * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
3614 * connect to the `mydb` database on `localhost` on port 3306, with the user
3615 * `root` and the password `password`. All tables will be prefixed with `sp_`
3616 *
3617 * @package SimplePie
3618 * @subpackage Caching
3619 */
3620class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
3621{
3622 /**
3623 * PDO instance
3624 *
3625 * @var PDO
3626 */
3627 protected $mysql;
3628
3629 /**
3630 * Options
3631 *
3632 * @var array
3633 */
3634 protected $options;
3635
3636 /**
3637 * Cache ID
3638 *
3639 * @var string
3640 */
3641 protected $id;
3642
3643 /**
3644 * Create a new cache object
3645 *
3646 * @param string $location Location string (from SimplePie::$cache_location)
3647 * @param string $name Unique ID for the cache
3648 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3649 */
3650 public function __construct($location, $name, $type)
3651 {
3652 $this->options = array(
3653 'user' => null,
3654 'pass' => null,
3655 'host' => '127.0.0.1',
3656 'port' => '3306',
3657 'path' => '',
3658 'extras' => array(
3659 'prefix' => '',
3660 ),
3661 );
3662 $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
3663
3664 // Path is prefixed with a "/"
3665 $this->options['dbname'] = substr($this->options['path'], 1);
3666
3667 try
f2f7b699 3668 {
a6e043ff 3669 $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
f2f7b699 3670 }
a6e043ff 3671 catch (PDOException $e)
f2f7b699 3672 {
a6e043ff
AD
3673 $this->mysql = null;
3674 return;
f2f7b699 3675 }
a6e043ff
AD
3676
3677 $this->id = $name . $type;
3678
3679 if (!$query = $this->mysql->query('SHOW TABLES'))
f2f7b699 3680 {
a6e043ff
AD
3681 $this->mysql = null;
3682 return;
f2f7b699 3683 }
a6e043ff
AD
3684
3685 $db = array();
3686 while ($row = $query->fetchColumn())
f2f7b699 3687 {
a6e043ff 3688 $db[] = $row;
f2f7b699 3689 }
f2f7b699 3690
a6e043ff 3691 if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
f2f7b699 3692 {
a6e043ff
AD
3693 $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
3694 if ($query === false)
3695 {
3696 $this->mysql = null;
3697 }
f2f7b699 3698 }
a6e043ff
AD
3699
3700 if (!in_array($this->options['extras']['prefix'] . 'items', $db))
f2f7b699 3701 {
a6e043ff
AD
3702 $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
3703 if ($query === false)
3704 {
3705 $this->mysql = null;
3706 }
f2f7b699
AD
3707 }
3708 }
3709
a6e043ff
AD
3710 /**
3711 * Save data to the cache
3712 *
3713 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3714 * @return bool Successfulness
3715 */
3716 public function save($data)
f2f7b699 3717 {
a6e043ff
AD
3718 if ($this->mysql === null)
3719 {
3720 return false;
3721 }
f2f7b699 3722
a6e043ff 3723 if ($data instanceof SimplePie)
f2f7b699 3724 {
a6e043ff
AD
3725 $data = clone $data;
3726
3727 $prepared = self::prepare_simplepie_object_for_cache($data);
3728
3729 $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
3730 $query->bindValue(':feed', $this->id);
3731 if ($query->execute())
f2f7b699 3732 {
a6e043ff
AD
3733 if ($query->fetchColumn() > 0)
3734 {
3735 $items = count($prepared[1]);
3736 if ($items)
3737 {
3738 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
3739 $query = $this->mysql->prepare($sql);
3740 $query->bindValue(':items', $items);
3741 }
3742 else
3743 {
3744 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
3745 $query = $this->mysql->prepare($sql);
3746 }
3747
3748 $query->bindValue(':data', $prepared[0]);
3749 $query->bindValue(':time', time());
3750 $query->bindValue(':feed', $this->id);
3751 if (!$query->execute())
3752 {
3753 return false;
3754 }
3755 }
3756 else
3757 {
3758 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
3759 $query->bindValue(':feed', $this->id);
3760 $query->bindValue(':count', count($prepared[1]));
3761 $query->bindValue(':data', $prepared[0]);
3762 $query->bindValue(':time', time());
3763 if (!$query->execute())
3764 {
3765 return false;
3766 }
3767 }
3768
3769 $ids = array_keys($prepared[1]);
3770 if (!empty($ids))
3771 {
3772 foreach ($ids as $id)
3773 {
3774 $database_ids[] = $this->mysql->quote($id);
3775 }
3776
3777 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
3778 $query->bindValue(':feed', $this->id);
3779
3780 if ($query->execute())
3781 {
3782 $existing_ids = array();
3783 while ($row = $query->fetchColumn())
3784 {
3785 $existing_ids[] = $row;
3786 }
3787
3788 $new_ids = array_diff($ids, $existing_ids);
3789
3790 foreach ($new_ids as $new_id)
3791 {
3792 if (!($date = $prepared[1][$new_id]->get_date('U')))
3793 {
3794 $date = time();
3795 }
3796
3797 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
3798 $query->bindValue(':feed', $this->id);
3799 $query->bindValue(':id', $new_id);
3800 $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
3801 $query->bindValue(':date', $date);
3802 if (!$query->execute())
3803 {
3804 return false;
3805 }
3806 }
3807 return true;
3808 }
3809 }
3810 else
3811 {
3812 return true;
3813 }
f2f7b699 3814 }
a6e043ff
AD
3815 }
3816 else
3817 {
3818 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
3819 $query->bindValue(':feed', $this->id);
3820 if ($query->execute())
f2f7b699 3821 {
a6e043ff
AD
3822 if ($query->rowCount() > 0)
3823 {
3824 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
3825 $query->bindValue(':data', serialize($data));
3826 $query->bindValue(':time', time());
3827 $query->bindValue(':feed', $this->id);
3828 if ($this->execute())
3829 {
3830 return true;
3831 }
3832 }
3833 else
3834 {
3835 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
3836 $query->bindValue(':id', $this->id);
3837 $query->bindValue(':data', serialize($data));
3838 $query->bindValue(':time', time());
3839 if ($query->execute())
3840 {
3841 return true;
3842 }
3843 }
f2f7b699 3844 }
f2f7b699 3845 }
a6e043ff
AD
3846 return false;
3847 }
3848
3849 /**
3850 * Retrieve the data saved to the cache
3851 *
3852 * @return array Data for SimplePie::$data
3853 */
3854 public function load()
3855 {
3856 if ($this->mysql === null)
f2f7b699 3857 {
a6e043ff
AD
3858 return false;
3859 }
3860
3861 $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3862 $query->bindValue(':id', $this->id);
3863 if ($query->execute() && ($row = $query->fetch()))
3864 {
3865 $data = unserialize($row[1]);
3866
3867 if (isset($this->options['items'][0]))
a5ae3915 3868 {
a6e043ff 3869 $items = (int) $this->options['items'][0];
a5ae3915
MK
3870 }
3871 else
3872 {
a6e043ff 3873 $items = (int) $row[0];
a5ae3915 3874 }
a6e043ff
AD
3875
3876 if ($items !== 0)
3877 {
3878 if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
3879 {
3880 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
3881 }
3882 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
3883 {
3884 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
3885 }
3886 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
3887 {
3888 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
3889 }
3890 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
3891 {
3892 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
3893 }
3894 else
3895 {
3896 $feed = null;
3897 }
3898
3899 if ($feed !== null)
3900 {
3901 $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
3902 if ($items > 0)
3903 {
3904 $sql .= ' LIMIT ' . $items;
3905 }
3906
3907 $query = $this->mysql->prepare($sql);
3908 $query->bindValue(':feed', $this->id);
3909 if ($query->execute())
3910 {
3911 while ($row = $query->fetchColumn())
3912 {
3913 $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
3914 }
3915 }
3916 else
3917 {
3918 return false;
3919 }
3920 }
3921 }
3922 return $data;
f2f7b699 3923 }
a6e043ff
AD
3924 return false;
3925 }
3926
3927 /**
3928 * Retrieve the last modified time for the cache
3929 *
3930 * @return int Timestamp
3931 */
3932 public function mtime()
3933 {
3934 if ($this->mysql === null)
f2f7b699 3935 {
a6e043ff 3936 return false;
f2f7b699
AD
3937 }
3938
a6e043ff
AD
3939 $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3940 $query->bindValue(':id', $this->id);
3941 if ($query->execute() && ($time = $query->fetchColumn()))
f2f7b699 3942 {
a6e043ff 3943 return $time;
f2f7b699
AD
3944 }
3945 else
3946 {
a6e043ff 3947 return false;
f2f7b699
AD
3948 }
3949 }
3950
a6e043ff
AD
3951 /**
3952 * Set the last modified time to the current time
3953 *
3954 * @return bool Success status
3955 */
3956 public function touch()
f2f7b699 3957 {
a6e043ff 3958 if ($this->mysql === null)
f2f7b699 3959 {
a6e043ff 3960 return false;
f2f7b699 3961 }
f2f7b699 3962
a6e043ff
AD
3963 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
3964 $query->bindValue(':time', time());
3965 $query->bindValue(':id', $this->id);
3966 if ($query->execute() && $query->rowCount() > 0)
6d7d21a0 3967 {
a6e043ff 3968 return true;
6d7d21a0
AD
3969 }
3970 else
3971 {
a6e043ff 3972 return false;
6d7d21a0
AD
3973 }
3974 }
3975
a6e043ff
AD
3976 /**
3977 * Remove the cache
3978 *
3979 * @return bool Success status
3980 */
3981 public function unlink()
6d7d21a0 3982 {
a6e043ff 3983 if ($this->mysql === null)
6d7d21a0 3984 {
a6e043ff 3985 return false;
6d7d21a0
AD
3986 }
3987
a6e043ff
AD
3988 $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3989 $query->bindValue(':id', $this->id);
3990 $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
3991 $query2->bindValue(':id', $this->id);
3992 if ($query->execute() && $query2->execute())
6d7d21a0 3993 {
a6e043ff 3994 return true;
6d7d21a0
AD
3995 }
3996 else
3997 {
a6e043ff 3998 return false;
6d7d21a0
AD
3999 }
4000 }
a6e043ff 4001}
6d7d21a0 4002
a6e043ff
AD
4003/**
4004 * Used to create cache objects
4005 *
4006 * This class can be overloaded with {@see SimplePie::set_cache_class()},
4007 * although the preferred way is to create your own handler
4008 * via {@see register()}
4009 *
4010 * @package SimplePie
4011 * @subpackage Caching
4012 */
4013class SimplePie_Cache
4014{
4015 /**
4016 * Cache handler classes
4017 *
4018 * These receive 3 parameters to their constructor, as documented in
4019 * {@see register()}
4020 * @var array
4021 */
4022 protected static $handlers = array(
4023 'mysql' => 'SimplePie_Cache_MySQL',
4024 'memcache' => 'SimplePie_Cache_Memcache',
4025 );
f2f7b699 4026
a6e043ff
AD
4027 /**
4028 * Don't call the constructor. Please.
4029 */
4030 private function __construct() { }
4031
4032 /**
4033 * Create a new SimplePie_Cache object
4034 *
4035 * @param string $location URL location (scheme is used to determine handler)
4036 * @param string $filename Unique identifier for cache object
4037 * @param string $extension 'spi' or 'spc'
4038 * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
4039 */
4040 public static function get_handler($location, $filename, $extension)
4041 {
4042 $type = explode(':', $location, 2);
4043 $type = $type[0];
4044 if (!empty(self::$handlers[$type]))
f2f7b699 4045 {
a6e043ff
AD
4046 $class = self::$handlers[$type];
4047 return new $class($location, $filename, $extension);
f2f7b699 4048 }
a6e043ff
AD
4049
4050 return new SimplePie_Cache_File($location, $filename, $extension);
4051 }
4052
4053 /**
4054 * Create a new SimplePie_Cache object
4055 *
4056 * @deprecated Use {@see get_handler} instead
4057 */
4058 public function create($location, $filename, $extension)
4059 {
4060 trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
4061 return self::get_handler($location, $filename, $extension);
4062 }
4063
4064 /**
4065 * Register a handler
4066 *
4067 * @param string $type DSN type to register for
4068 * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
4069 */
4070 public static function register($type, $class)
4071 {
4072 self::$handlers[$type] = $class;
4073 }
4074
4075 /**
4076 * Parse a URL into an array
4077 *
4078 * @param string $url
4079 * @return array
4080 */
4081 public static function parse_URL($url)
4082 {
4083 $params = parse_url($url);
4084 $params['extras'] = array();
4085 if (isset($params['query']))
6d7d21a0 4086 {
a6e043ff 4087 parse_str($params['query'], $params['extras']);
6d7d21a0 4088 }
a6e043ff
AD
4089 return $params;
4090 }
4091}
4092
4093/**
4094 * Handles `<media:text>` captions as defined in Media RSS.
4095 *
4096 * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
4097 *
4098 * This class can be overloaded with {@see SimplePie::set_caption_class()}
4099 *
4100 * @package SimplePie
4101 * @subpackage API
4102 */
4103class SimplePie_Caption
4104{
4105 /**
4106 * Content type
4107 *
4108 * @var string
4109 * @see get_type()
4110 */
4111 var $type;
4112
4113 /**
4114 * Language
4115 *
4116 * @var string
4117 * @see get_language()
4118 */
4119 var $lang;
4120
4121 /**
4122 * Start time
4123 *
4124 * @var string
4125 * @see get_starttime()
4126 */
4127 var $startTime;
4128
4129 /**
4130 * End time
4131 *
4132 * @var string
4133 * @see get_endtime()
4134 */
4135 var $endTime;
4136
4137 /**
4138 * Caption text
4139 *
4140 * @var string
4141 * @see get_text()
4142 */
4143 var $text;
4144
4145 /**
4146 * Constructor, used to input the data
4147 *
4148 * For documentation on all the parameters, see the corresponding
4149 * properties and their accessors
4150 */
4151 public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
4152 {
4153 $this->type = $type;
4154 $this->lang = $lang;
4155 $this->startTime = $startTime;
4156 $this->endTime = $endTime;
4157 $this->text = $text;
4158 }
4159
4160 /**
4161 * String-ified version
4162 *
4163 * @return string
4164 */
4165 public function __toString()
4166 {
4167 // There is no $this->data here
4168 return md5(serialize($this));
4169 }
4170
4171 /**
4172 * Get the end time
4173 *
4174 * @return string|null Time in the format 'hh:mm:ss.SSS'
4175 */
4176 public function get_endtime()
4177 {
4178 if ($this->endTime !== null)
6d7d21a0 4179 {
a6e043ff 4180 return $this->endTime;
6d7d21a0
AD
4181 }
4182 else
4183 {
4184 return null;
4185 }
4186 }
4187
a6e043ff
AD
4188 /**
4189 * Get the language
4190 *
4191 * @link http://tools.ietf.org/html/rfc3066
4192 * @return string|null Language code as per RFC 3066
4193 */
4194 public function get_language()
6d7d21a0 4195 {
a6e043ff 4196 if ($this->lang !== null)
6d7d21a0 4197 {
a6e043ff 4198 return $this->lang;
6d7d21a0 4199 }
f2f7b699
AD
4200 else
4201 {
4202 return null;
4203 }
4204 }
4205
a6e043ff
AD
4206 /**
4207 * Get the start time
4208 *
4209 * @return string|null Time in the format 'hh:mm:ss.SSS'
4210 */
4211 public function get_starttime()
f2f7b699 4212 {
a6e043ff 4213 if ($this->startTime !== null)
f2f7b699 4214 {
a6e043ff 4215 return $this->startTime;
f2f7b699
AD
4216 }
4217 else
4218 {
4219 return null;
4220 }
4221 }
4222
a6e043ff
AD
4223 /**
4224 * Get the text of the caption
4225 *
4226 * @return string|null
4227 */
4228 public function get_text()
f2f7b699 4229 {
a6e043ff 4230 if ($this->text !== null)
f2f7b699 4231 {
a6e043ff 4232 return $this->text;
f2f7b699
AD
4233 }
4234 else
4235 {
4236 return null;
4237 }
4238 }
4239
a6e043ff
AD
4240 /**
4241 * Get the content type (not MIME type)
4242 *
4243 * @return string|null Either 'text' or 'html'
4244 */
4245 public function get_type()
f2f7b699 4246 {
a6e043ff 4247 if ($this->type !== null)
f2f7b699 4248 {
a6e043ff 4249 return $this->type;
f2f7b699
AD
4250 }
4251 else
4252 {
4253 return null;
4254 }
4255 }
a6e043ff 4256}
f2f7b699 4257
a6e043ff
AD
4258/**
4259 * Manages all category-related data
4260 *
4261 * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
4262 *
4263 * This class can be overloaded with {@see SimplePie::set_category_class()}
4264 *
4265 * @package SimplePie
4266 * @subpackage API
4267 */
4268class SimplePie_Category
4269{
4270 /**
4271 * Category identifier
4272 *
4273 * @var string
4274 * @see get_term
4275 */
4276 var $term;
4277
4278 /**
4279 * Categorization scheme identifier
4280 *
4281 * @var string
4282 * @see get_scheme()
4283 */
4284 var $scheme;
4285
4286 /**
4287 * Human readable label
4288 *
4289 * @var string
4290 * @see get_label()
4291 */
4292 var $label;
4293
4294 /**
4295 * Constructor, used to input the data
4296 *
4297 * @param string $term
4298 * @param string $scheme
4299 * @param string $label
4300 */
4301 public function __construct($term = null, $scheme = null, $label = null)
4302 {
4303 $this->term = $term;
4304 $this->scheme = $scheme;
4305 $this->label = $label;
4306 }
4307
4308 /**
4309 * String-ified version
4310 *
4311 * @return string
4312 */
4313 public function __toString()
4314 {
4315 // There is no $this->data here
4316 return md5(serialize($this));
4317 }
4318
4319 /**
4320 * Get the category identifier
4321 *
4322 * @return string|null
4323 */
4324 public function get_term()
4325 {
4326 if ($this->term !== null)
f2f7b699 4327 {
a6e043ff 4328 return $this->term;
f2f7b699
AD
4329 }
4330 else
4331 {
4332 return null;
4333 }
4334 }
4335
a6e043ff
AD
4336 /**
4337 * Get the categorization scheme identifier
4338 *
4339 * @return string|null
4340 */
4341 public function get_scheme()
f2f7b699 4342 {
a6e043ff 4343 if ($this->scheme !== null)
f2f7b699 4344 {
a6e043ff
AD
4345 return $this->scheme;
4346 }
4347 else
4348 {
4349 return null;
4350 }
4351 }
f2f7b699 4352
a6e043ff
AD
4353 /**
4354 * Get the human readable label
4355 *
4356 * @return string|null
4357 */
4358 public function get_label()
4359 {
4360 if ($this->label !== null)
4361 {
4362 return $this->label;
4363 }
4364 else
4365 {
4366 return $this->get_term();
4367 }
4368 }
4369}
4370
4371/**
4372 * Content-type sniffing
4373 *
4374 * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
4375 *
4376 * This is used since we can't always trust Content-Type headers, and is based
4377 * upon the HTML5 parsing rules.
4378 *
4379 *
4380 * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
4381 *
4382 * @package SimplePie
4383 * @subpackage HTTP
4384 */
4385class SimplePie_Content_Type_Sniffer
4386{
4387 /**
4388 * File object
4389 *
4390 * @var SimplePie_File
4391 */
4392 var $file;
4393
4394 /**
4395 * Create an instance of the class with the input file
4396 *
4397 * @param SimplePie_Content_Type_Sniffer $file Input file
4398 */
4399 public function __construct($file)
4400 {
4401 $this->file = $file;
4402 }
4403
4404 /**
4405 * Get the Content-Type of the specified file
4406 *
4407 * @return string Actual Content-Type
4408 */
4409 public function get_type()
4410 {
4411 if (isset($this->file->headers['content-type']))
4412 {
4413 if (!isset($this->file->headers['content-encoding'])
4414 && ($this->file->headers['content-type'] === 'text/plain'
4415 || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
4416 || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
4417 || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
f2f7b699 4418 {
a6e043ff 4419 return $this->text_or_binary();
f2f7b699 4420 }
a6e043ff
AD
4421
4422 if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
f2f7b699 4423 {
a6e043ff 4424 $official = substr($this->file->headers['content-type'], 0, $pos);
f2f7b699 4425 }
a6e043ff 4426 else
f2f7b699 4427 {
a6e043ff 4428 $official = $this->file->headers['content-type'];
f2f7b699 4429 }
a6e043ff
AD
4430 $official = trim(strtolower($official));
4431
4432 if ($official === 'unknown/unknown'
4433 || $official === 'application/unknown')
f2f7b699 4434 {
a6e043ff 4435 return $this->unknown();
f2f7b699 4436 }
a6e043ff
AD
4437 elseif (substr($official, -4) === '+xml'
4438 || $official === 'text/xml'
4439 || $official === 'application/xml')
f2f7b699 4440 {
a6e043ff 4441 return $official;
f2f7b699 4442 }
a6e043ff 4443 elseif (substr($official, 0, 6) === 'image/')
f2f7b699 4444 {
a6e043ff 4445 if ($return = $this->image())
f2f7b699 4446 {
a6e043ff 4447 return $return;
f2f7b699 4448 }
a6e043ff 4449 else
f2f7b699 4450 {
a6e043ff 4451 return $official;
f2f7b699 4452 }
f2f7b699 4453 }
a6e043ff
AD
4454 elseif ($official === 'text/html')
4455 {
4456 return $this->feed_or_html();
4457 }
4458 else
4459 {
4460 return $official;
4461 }
f2f7b699
AD
4462 }
4463 else
4464 {
a6e043ff 4465 return $this->unknown();
f2f7b699
AD
4466 }
4467 }
4468
4469 /**
a6e043ff
AD
4470 * Sniff text or binary
4471 *
4472 * @return string Actual Content-Type
f2f7b699 4473 */
a6e043ff 4474 public function text_or_binary()
f2f7b699 4475 {
a6e043ff
AD
4476 if (substr($this->file->body, 0, 2) === "\xFE\xFF"
4477 || substr($this->file->body, 0, 2) === "\xFF\xFE"
4478 || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
4479 || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
f2f7b699 4480 {
a6e043ff
AD
4481 return 'text/plain';
4482 }
4483 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
4484 {
4485 return 'application/octect-stream';
f2f7b699
AD
4486 }
4487 else
4488 {
a6e043ff 4489 return 'text/plain';
f2f7b699
AD
4490 }
4491 }
4492
4493 /**
a6e043ff 4494 * Sniff unknown
f2f7b699 4495 *
a6e043ff 4496 * @return string Actual Content-Type
f2f7b699 4497 */
a6e043ff 4498 public function unknown()
f2f7b699 4499 {
a6e043ff
AD
4500 $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
4501 if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
4502 || strtolower(substr($this->file->body, $ws, 5)) === '<html'
4503 || strtolower(substr($this->file->body, $ws, 7)) === '<script')
f2f7b699 4504 {
a6e043ff
AD
4505 return 'text/html';
4506 }
4507 elseif (substr($this->file->body, 0, 5) === '%PDF-')
4508 {
4509 return 'application/pdf';
4510 }
4511 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
4512 {
4513 return 'application/postscript';
4514 }
4515 elseif (substr($this->file->body, 0, 6) === 'GIF87a'
4516 || substr($this->file->body, 0, 6) === 'GIF89a')
4517 {
4518 return 'image/gif';
4519 }
4520 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4521 {
4522 return 'image/png';
4523 }
4524 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4525 {
4526 return 'image/jpeg';
4527 }
4528 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4529 {
4530 return 'image/bmp';
4531 }
4532 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4533 {
4534 return 'image/vnd.microsoft.icon';
4535 }
4536 else
4537 {
4538 return $this->text_or_binary();
4539 }
4540 }
4541
4542 /**
4543 * Sniff images
4544 *
4545 * @return string Actual Content-Type
4546 */
4547 public function image()
4548 {
4549 if (substr($this->file->body, 0, 6) === 'GIF87a'
4550 || substr($this->file->body, 0, 6) === 'GIF89a')
4551 {
4552 return 'image/gif';
4553 }
4554 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4555 {
4556 return 'image/png';
4557 }
4558 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4559 {
4560 return 'image/jpeg';
4561 }
4562 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4563 {
4564 return 'image/bmp';
4565 }
4566 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4567 {
4568 return 'image/vnd.microsoft.icon';
4569 }
4570 else
4571 {
4572 return false;
4573 }
4574 }
4575
4576 /**
4577 * Sniff HTML
4578 *
4579 * @return string Actual Content-Type
4580 */
4581 public function feed_or_html()
4582 {
4583 $len = strlen($this->file->body);
4584 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
4585
4586 while ($pos < $len)
4587 {
4588 switch ($this->file->body[$pos])
f2f7b699 4589 {
a6e043ff
AD
4590 case "\x09":
4591 case "\x0A":
4592 case "\x0D":
4593 case "\x20":
4594 $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
4595 continue 2;
4596
4597 case '<':
4598 $pos++;
4599 break;
4600
4601 default:
4602 return 'text/html';
f2f7b699
AD
4603 }
4604
a6e043ff 4605 if (substr($this->file->body, $pos, 3) === '!--')
f2f7b699 4606 {
a6e043ff
AD
4607 $pos += 3;
4608 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
f2f7b699 4609 {
a6e043ff 4610 $pos += 3;
f2f7b699
AD
4611 }
4612 else
4613 {
a6e043ff 4614 return 'text/html';
f2f7b699 4615 }
f2f7b699 4616 }
a6e043ff 4617 elseif (substr($this->file->body, $pos, 1) === '!')
f2f7b699 4618 {
a6e043ff 4619 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
f2f7b699 4620 {
a6e043ff 4621 $pos++;
f2f7b699
AD
4622 }
4623 else
4624 {
a6e043ff 4625 return 'text/html';
f2f7b699 4626 }
f2f7b699 4627 }
a6e043ff 4628 elseif (substr($this->file->body, $pos, 1) === '?')
f2f7b699 4629 {
a6e043ff 4630 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
f2f7b699 4631 {
a6e043ff 4632 $pos += 2;
f2f7b699 4633 }
a6e043ff 4634 else
f2f7b699 4635 {
a6e043ff 4636 return 'text/html';
f2f7b699
AD
4637 }
4638 }
a6e043ff
AD
4639 elseif (substr($this->file->body, $pos, 3) === 'rss'
4640 || substr($this->file->body, $pos, 7) === 'rdf:RDF')
f2f7b699 4641 {
a6e043ff 4642 return 'application/rss+xml';
f2f7b699 4643 }
a6e043ff 4644 elseif (substr($this->file->body, $pos, 4) === 'feed')
f2f7b699 4645 {
a6e043ff 4646 return 'application/atom+xml';
f2f7b699 4647 }
a6e043ff 4648 else
f2f7b699 4649 {
a6e043ff 4650 return 'text/html';
f2f7b699 4651 }
a6e043ff 4652 }
f2f7b699 4653
a6e043ff
AD
4654 return 'text/html';
4655 }
4656}
f2f7b699 4657
a6e043ff
AD
4658/**
4659 * Manages `<media:copyright>` copyright tags as defined in Media RSS
4660 *
4661 * Used by {@see SimplePie_Enclosure::get_copyright()}
4662 *
4663 * This class can be overloaded with {@see SimplePie::set_copyright_class()}
4664 *
4665 * @package SimplePie
4666 * @subpackage API
4667 */
4668class SimplePie_Copyright
4669{
4670 /**
4671 * Copyright URL
4672 *
4673 * @var string
4674 * @see get_url()
4675 */
4676 var $url;
f2f7b699 4677
a6e043ff
AD
4678 /**
4679 * Attribution
4680 *
4681 * @var string
4682 * @see get_attribution()
4683 */
4684 var $label;
f2f7b699 4685
a6e043ff
AD
4686 /**
4687 * Constructor, used to input the data
4688 *
4689 * For documentation on all the parameters, see the corresponding
4690 * properties and their accessors
4691 */
4692 public function __construct($url = null, $label = null)
4693 {
4694 $this->url = $url;
4695 $this->label = $label;
4696 }
f2f7b699 4697
a6e043ff
AD
4698 /**
4699 * String-ified version
4700 *
4701 * @return string
4702 */
4703 public function __toString()
4704 {
4705 // There is no $this->data here
4706 return md5(serialize($this));
4707 }
f2f7b699 4708
a6e043ff
AD
4709 /**
4710 * Get the copyright URL
4711 *
4712 * @return string|null URL to copyright information
4713 */
4714 public function get_url()
4715 {
4716 if ($this->url !== null)
4717 {
4718 return $this->url;
4719 }
4720 else
4721 {
4722 return null;
4723 }
4724 }
f2f7b699 4725
a6e043ff
AD
4726 /**
4727 * Get the attribution text
4728 *
4729 * @return string|null
4730 */
4731 public function get_attribution()
4732 {
4733 if ($this->label !== null)
4734 {
4735 return $this->label;
4736 }
4737 else
4738 {
4739 return null;
4740 }
4741 }
4742}
f2f7b699 4743
a6e043ff
AD
4744/**
4745 * SimplePie class.
4746 *
4747 * Class for backward compatibility.
4748 *
4749 * @deprecated Use {@see SimplePie} directly
4750 * @package SimplePie
4751 * @subpackage API
4752 */
4753class SimplePie_Core extends SimplePie
4754{
f2f7b699 4755
a6e043ff 4756}
f2f7b699 4757
a6e043ff
AD
4758/**
4759 * Handles `<media:credit>` as defined in Media RSS
4760 *
4761 * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
4762 *
4763 * This class can be overloaded with {@see SimplePie::set_credit_class()}
4764 *
4765 * @package SimplePie
4766 * @subpackage API
4767 */
4768class SimplePie_Credit
4769{
4770 /**
4771 * Credited role
4772 *
4773 * @var string
4774 * @see get_role()
4775 */
4776 var $role;
f2f7b699 4777
a6e043ff
AD
4778 /**
4779 * Organizational scheme
4780 *
4781 * @var string
4782 * @see get_scheme()
4783 */
4784 var $scheme;
f2f7b699 4785
a6e043ff
AD
4786 /**
4787 * Credited name
4788 *
4789 * @var string
4790 * @see get_name()
4791 */
4792 var $name;
3cae90e1 4793
a6e043ff
AD
4794 /**
4795 * Constructor, used to input the data
4796 *
4797 * For documentation on all the parameters, see the corresponding
4798 * properties and their accessors
4799 */
4800 public function __construct($role = null, $scheme = null, $name = null)
4801 {
4802 $this->role = $role;
4803 $this->scheme = $scheme;
4804 $this->name = $name;
4805 }
3cae90e1 4806
a6e043ff
AD
4807 /**
4808 * String-ified version
4809 *
4810 * @return string
4811 */
4812 public function __toString()
4813 {
4814 // There is no $this->data here
4815 return md5(serialize($this));
4816 }
5b085627 4817
a6e043ff
AD
4818 /**
4819 * Get the role of the person receiving credit
4820 *
4821 * @return string|null
4822 */
4823 public function get_role()
4824 {
4825 if ($this->role !== null)
4826 {
4827 return $this->role;
4828 }
4829 else
4830 {
4831 return null;
4832 }
4833 }
5b085627 4834
a6e043ff
AD
4835 /**
4836 * Get the organizational scheme
4837 *
4838 * @return string|null
4839 */
4840 public function get_scheme()
4841 {
4842 if ($this->scheme !== null)
4843 {
4844 return $this->scheme;
4845 }
4846 else
4847 {
4848 return null;
4849 }
4850 }
f2f7b699 4851
a6e043ff
AD
4852 /**
4853 * Get the credited person/entity's name
4854 *
4855 * @return string|null
4856 */
4857 public function get_name()
4858 {
4859 if ($this->name !== null)
4860 {
4861 return $this->name;
4862 }
4863 else
4864 {
4865 return null;
4866 }
4867 }
4868}
5b085627 4869
a6e043ff
AD
4870/**
4871 * Decode HTML Entities
4872 *
4873 * This implements HTML5 as of revision 967 (2007-06-28)
4874 *
4875 * @deprecated Use DOMDocument instead!
4876 * @package SimplePie
4877 */
4878class SimplePie_Decode_HTML_Entities
4879{
4880 /**
4881 * Data to be parsed
4882 *
4883 * @access private
4884 * @var string
4885 */
4886 var $data = '';
5b085627 4887
a6e043ff
AD
4888 /**
4889 * Currently consumed bytes
4890 *
4891 * @access private
4892 * @var string
4893 */
4894 var $consumed = '';
f2f7b699 4895
a6e043ff
AD
4896 /**
4897 * Position of the current byte being parsed
4898 *
4899 * @access private
4900 * @var int
4901 */
4902 var $position = 0;
5b085627 4903
a6e043ff
AD
4904 /**
4905 * Create an instance of the class with the input data
4906 *
4907 * @access public
4908 * @param string $data Input data
4909 */
4910 public function __construct($data)
4911 {
4912 $this->data = $data;
4913 }
f2f7b699 4914
a6e043ff
AD
4915 /**
4916 * Parse the input data
4917 *
4918 * @access public
4919 * @return string Output data
4920 */
4921 public function parse()
4922 {
4923 while (($this->position = strpos($this->data, '&', $this->position)) !== false)
4924 {
4925 $this->consume();
4926 $this->entity();
4927 $this->consumed = '';
4928 }
4929 return $this->data;
4930 }
5b085627 4931
a6e043ff
AD
4932 /**
4933 * Consume the next byte
4934 *
4935 * @access private
4936 * @return mixed The next byte, or false, if there is no more data
4937 */
4938 public function consume()
4939 {
4940 if (isset($this->data[$this->position]))
4941 {
4942 $this->consumed .= $this->data[$this->position];
4943 return $this->data[$this->position++];
4944 }
4945 else
4946 {
4947 return false;
4948 }
4949 }
f2f7b699 4950
a6e043ff
AD
4951 /**
4952 * Consume a range of characters
4953 *
4954 * @access private
4955 * @param string $chars Characters to consume
4956 * @return mixed A series of characters that match the range, or false
4957 */
4958 public function consume_range($chars)
4959 {
4960 if ($len = strspn($this->data, $chars, $this->position))
4961 {
4962 $data = substr($this->data, $this->position, $len);
4963 $this->consumed .= $data;
4964 $this->position += $len;
4965 return $data;
4966 }
4967 else
4968 {
4969 return false;
4970 }
4971 }
5b085627 4972
a6e043ff
AD
4973 /**
4974 * Unconsume one byte
4975 *
4976 * @access private
4977 */
4978 public function unconsume()
4979 {
4980 $this->consumed = substr($this->consumed, 0, -1);
4981 $this->position--;
4982 }
5b085627 4983
a6e043ff
AD
4984 /**
4985 * Decode an entity
4986 *
4987 * @access private
4988 */
4989 public function entity()
4990 {
4991 switch ($this->consume())
4992 {
4993 case "\x09":
4994 case "\x0A":
4995 case "\x0B":
4996 case "\x0B":
4997 case "\x0C":
4998 case "\x20":
4999 case "\x3C":
5000 case "\x26":
5001 case false:
5002 break;
f2f7b699 5003
a6e043ff
AD
5004 case "\x23":
5005 switch ($this->consume())
5006 {
5007 case "\x78":
5008 case "\x58":
5009 $range = '0123456789ABCDEFabcdef';
5010 $hex = true;
5011 break;
5b085627 5012
a6e043ff
AD
5013 default:
5014 $range = '0123456789';
5015 $hex = false;
5016 $this->unconsume();
5017 break;
5018 }
f2f7b699 5019
a6e043ff
AD
5020 if ($codepoint = $this->consume_range($range))
5021 {
5022 static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
f2f7b699 5023
a6e043ff
AD
5024 if ($hex)
5025 {
5026 $codepoint = hexdec($codepoint);
5027 }
5028 else
5029 {
5030 $codepoint = intval($codepoint);
f2f7b699 5031 }
f2f7b699 5032
a6e043ff 5033 if (isset($windows_1252_specials[$codepoint]))
f2f7b699 5034 {
a6e043ff
AD
5035 $replacement = $windows_1252_specials[$codepoint];
5036 }
5037 else
5038 {
5039 $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
5040 }
f2f7b699 5041
a6e043ff
AD
5042 if (!in_array($this->consume(), array(';', false), true))
5043 {
5044 $this->unconsume();
5045 }
f2f7b699 5046
a6e043ff
AD
5047 $consumed_length = strlen($this->consumed);
5048 $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
5049 $this->position += strlen($replacement) - $consumed_length;
5050 }
5051 break;
f2f7b699 5052
a6e043ff
AD
5053 default:
5054 static $entities = array(
5055 'Aacute' => "\xC3\x81",
5056 'aacute' => "\xC3\xA1",
5057 'Aacute;' => "\xC3\x81",
5058 'aacute;' => "\xC3\xA1",
5059 'Acirc' => "\xC3\x82",
5060 'acirc' => "\xC3\xA2",
5061 'Acirc;' => "\xC3\x82",
5062 'acirc;' => "\xC3\xA2",
5063 'acute' => "\xC2\xB4",
5064 'acute;' => "\xC2\xB4",
5065 'AElig' => "\xC3\x86",
5066 'aelig' => "\xC3\xA6",
5067 'AElig;' => "\xC3\x86",
5068 'aelig;' => "\xC3\xA6",
5069 'Agrave' => "\xC3\x80",
5070 'agrave' => "\xC3\xA0",
5071 'Agrave;' => "\xC3\x80",
5072 'agrave;' => "\xC3\xA0",
5073 'alefsym;' => "\xE2\x84\xB5",
5074 'Alpha;' => "\xCE\x91",
5075 'alpha;' => "\xCE\xB1",
5076 'AMP' => "\x26",
5077 'amp' => "\x26",
5078 'AMP;' => "\x26",
5079 'amp;' => "\x26",
5080 'and;' => "\xE2\x88\xA7",
5081 'ang;' => "\xE2\x88\xA0",
5082 'apos;' => "\x27",
5083 'Aring' => "\xC3\x85",
5084 'aring' => "\xC3\xA5",
5085 'Aring;' => "\xC3\x85",
5086 'aring;' => "\xC3\xA5",
5087 'asymp;' => "\xE2\x89\x88",
5088 'Atilde' => "\xC3\x83",
5089 'atilde' => "\xC3\xA3",
5090 'Atilde;' => "\xC3\x83",
5091 'atilde;' => "\xC3\xA3",
5092 'Auml' => "\xC3\x84",
5093 'auml' => "\xC3\xA4",
5094 'Auml;' => "\xC3\x84",
5095 'auml;' => "\xC3\xA4",
5096 'bdquo;' => "\xE2\x80\x9E",
5097 'Beta;' => "\xCE\x92",
5098 'beta;' => "\xCE\xB2",
5099 'brvbar' => "\xC2\xA6",
5100 'brvbar;' => "\xC2\xA6",
5101 'bull;' => "\xE2\x80\xA2",
5102 'cap;' => "\xE2\x88\xA9",
5103 'Ccedil' => "\xC3\x87",
5104 'ccedil' => "\xC3\xA7",
5105 'Ccedil;' => "\xC3\x87",
5106 'ccedil;' => "\xC3\xA7",
5107 'cedil' => "\xC2\xB8",
5108 'cedil;' => "\xC2\xB8",
5109 'cent' => "\xC2\xA2",
5110 'cent;' => "\xC2\xA2",
5111 'Chi;' => "\xCE\xA7",
5112 'chi;' => "\xCF\x87",
5113 'circ;' => "\xCB\x86",
5114 'clubs;' => "\xE2\x99\xA3",
5115 'cong;' => "\xE2\x89\x85",
5116 'COPY' => "\xC2\xA9",
5117 'copy' => "\xC2\xA9",
5118 'COPY;' => "\xC2\xA9",
5119 'copy;' => "\xC2\xA9",
5120 'crarr;' => "\xE2\x86\xB5",
5121 'cup;' => "\xE2\x88\xAA",
5122 'curren' => "\xC2\xA4",
5123 'curren;' => "\xC2\xA4",
5124 'Dagger;' => "\xE2\x80\xA1",
5125 'dagger;' => "\xE2\x80\xA0",
5126 'dArr;' => "\xE2\x87\x93",
5127 'darr;' => "\xE2\x86\x93",
5128 'deg' => "\xC2\xB0",
5129 'deg;' => "\xC2\xB0",
5130 'Delta;' => "\xCE\x94",
5131 'delta;' => "\xCE\xB4",
5132 'diams;' => "\xE2\x99\xA6",
5133 'divide' => "\xC3\xB7",
5134 'divide;' => "\xC3\xB7",
5135 'Eacute' => "\xC3\x89",
5136 'eacute' => "\xC3\xA9",
5137 'Eacute;' => "\xC3\x89",
5138 'eacute;' => "\xC3\xA9",
5139 'Ecirc' => "\xC3\x8A",
5140 'ecirc' => "\xC3\xAA",
5141 'Ecirc;' => "\xC3\x8A",
5142 'ecirc;' => "\xC3\xAA",
5143 'Egrave' => "\xC3\x88",
5144 'egrave' => "\xC3\xA8",
5145 'Egrave;' => "\xC3\x88",
5146 'egrave;' => "\xC3\xA8",
5147 'empty;' => "\xE2\x88\x85",
5148 'emsp;' => "\xE2\x80\x83",
5149 'ensp;' => "\xE2\x80\x82",
5150 'Epsilon;' => "\xCE\x95",
5151 'epsilon;' => "\xCE\xB5",
5152 'equiv;' => "\xE2\x89\xA1",
5153 'Eta;' => "\xCE\x97",
5154 'eta;' => "\xCE\xB7",
5155 'ETH' => "\xC3\x90",
5156 'eth' => "\xC3\xB0",
5157 'ETH;' => "\xC3\x90",
5158 'eth;' => "\xC3\xB0",
5159 'Euml' => "\xC3\x8B",
5160 'euml' => "\xC3\xAB",
5161 'Euml;' => "\xC3\x8B",
5162 'euml;' => "\xC3\xAB",
5163 'euro;' => "\xE2\x82\xAC",
5164 'exist;' => "\xE2\x88\x83",
5165 'fnof;' => "\xC6\x92",
5166 'forall;' => "\xE2\x88\x80",
5167 'frac12' => "\xC2\xBD",
5168 'frac12;' => "\xC2\xBD",
5169 'frac14' => "\xC2\xBC",
5170 'frac14;' => "\xC2\xBC",
5171 'frac34' => "\xC2\xBE",
5172 'frac34;' => "\xC2\xBE",
5173 'frasl;' => "\xE2\x81\x84",
5174 'Gamma;' => "\xCE\x93",
5175 'gamma;' => "\xCE\xB3",
5176 'ge;' => "\xE2\x89\xA5",
5177 'GT' => "\x3E",
5178 'gt' => "\x3E",
5179 'GT;' => "\x3E",
5180 'gt;' => "\x3E",
5181 'hArr;' => "\xE2\x87\x94",
5182 'harr;' => "\xE2\x86\x94",
5183 'hearts;' => "\xE2\x99\xA5",
5184 'hellip;' => "\xE2\x80\xA6",
5185 'Iacute' => "\xC3\x8D",
5186 'iacute' => "\xC3\xAD",
5187 'Iacute;' => "\xC3\x8D",
5188 'iacute;' => "\xC3\xAD",
5189 'Icirc' => "\xC3\x8E",
5190 'icirc' => "\xC3\xAE",
5191 'Icirc;' => "\xC3\x8E",
5192 'icirc;' => "\xC3\xAE",
5193 'iexcl' => "\xC2\xA1",
5194 'iexcl;' => "\xC2\xA1",
5195 'Igrave' => "\xC3\x8C",
5196 'igrave' => "\xC3\xAC",
5197 'Igrave;' => "\xC3\x8C",
5198 'igrave;' => "\xC3\xAC",
5199 'image;' => "\xE2\x84\x91",
5200 'infin;' => "\xE2\x88\x9E",
5201 'int;' => "\xE2\x88\xAB",
5202 'Iota;' => "\xCE\x99",
5203 'iota;' => "\xCE\xB9",
5204 'iquest' => "\xC2\xBF",
5205 'iquest;' => "\xC2\xBF",
5206 'isin;' => "\xE2\x88\x88",
5207 'Iuml' => "\xC3\x8F",
5208 'iuml' => "\xC3\xAF",
5209 'Iuml;' => "\xC3\x8F",
5210 'iuml;' => "\xC3\xAF",
5211 'Kappa;' => "\xCE\x9A",
5212 'kappa;' => "\xCE\xBA",
5213 'Lambda;' => "\xCE\x9B",
5214 'lambda;' => "\xCE\xBB",
5215 'lang;' => "\xE3\x80\x88",
5216 'laquo' => "\xC2\xAB",
5217 'laquo;' => "\xC2\xAB",
5218 'lArr;' => "\xE2\x87\x90",
5219 'larr;' => "\xE2\x86\x90",
5220 'lceil;' => "\xE2\x8C\x88",
5221 'ldquo;' => "\xE2\x80\x9C",
5222 'le;' => "\xE2\x89\xA4",
5223 'lfloor;' => "\xE2\x8C\x8A",
5224 'lowast;' => "\xE2\x88\x97",
5225 'loz;' => "\xE2\x97\x8A",
5226 'lrm;' => "\xE2\x80\x8E",
5227 'lsaquo;' => "\xE2\x80\xB9",
5228 'lsquo;' => "\xE2\x80\x98",
5229 'LT' => "\x3C",
5230 'lt' => "\x3C",
5231 'LT;' => "\x3C",
5232 'lt;' => "\x3C",
5233 'macr' => "\xC2\xAF",
5234 'macr;' => "\xC2\xAF",
5235 'mdash;' => "\xE2\x80\x94",
5236 'micro' => "\xC2\xB5",
5237 'micro;' => "\xC2\xB5",
5238 'middot' => "\xC2\xB7",
5239 'middot;' => "\xC2\xB7",
5240 'minus;' => "\xE2\x88\x92",
5241 'Mu;' => "\xCE\x9C",
5242 'mu;' => "\xCE\xBC",
5243 'nabla;' => "\xE2\x88\x87",
5244 'nbsp' => "\xC2\xA0",
5245 'nbsp;' => "\xC2\xA0",
5246 'ndash;' => "\xE2\x80\x93",
5247 'ne;' => "\xE2\x89\xA0",
5248 'ni;' => "\xE2\x88\x8B",
5249 'not' => "\xC2\xAC",
5250 'not;' => "\xC2\xAC",
5251 'notin;' => "\xE2\x88\x89",
5252 'nsub;' => "\xE2\x8A\x84",
5253 'Ntilde' => "\xC3\x91",
5254 'ntilde' => "\xC3\xB1",
5255 'Ntilde;' => "\xC3\x91",
5256 'ntilde;' => "\xC3\xB1",
5257 'Nu;' => "\xCE\x9D",
5258 'nu;' => "\xCE\xBD",
5259 'Oacute' => "\xC3\x93",
5260 'oacute' => "\xC3\xB3",
5261 'Oacute;' => "\xC3\x93",
5262 'oacute;' => "\xC3\xB3",
5263 'Ocirc' => "\xC3\x94",
5264 'ocirc' => "\xC3\xB4",
5265 'Ocirc;' => "\xC3\x94",
5266 'ocirc;' => "\xC3\xB4",
5267 'OElig;' => "\xC5\x92",
5268 'oelig;' => "\xC5\x93",
5269 'Ograve' => "\xC3\x92",
5270 'ograve' => "\xC3\xB2",
5271 'Ograve;' => "\xC3\x92",
5272 'ograve;' => "\xC3\xB2",
5273 'oline;' => "\xE2\x80\xBE",
5274 'Omega;' => "\xCE\xA9",
5275 'omega;' => "\xCF\x89",
5276 'Omicron;' => "\xCE\x9F",
5277 'omicron;' => "\xCE\xBF",
5278 'oplus;' => "\xE2\x8A\x95",
5279 'or;' => "\xE2\x88\xA8",
5280 'ordf' => "\xC2\xAA",
5281 'ordf;' => "\xC2\xAA",
5282 'ordm' => "\xC2\xBA",
5283 'ordm;' => "\xC2\xBA",
5284 'Oslash' => "\xC3\x98",
5285 'oslash' => "\xC3\xB8",
5286 'Oslash;' => "\xC3\x98",
5287 'oslash;' => "\xC3\xB8",
5288 'Otilde' => "\xC3\x95",
5289 'otilde' => "\xC3\xB5",
5290 'Otilde;' => "\xC3\x95",
5291 'otilde;' => "\xC3\xB5",
5292 'otimes;' => "\xE2\x8A\x97",
5293 'Ouml' => "\xC3\x96",
5294 'ouml' => "\xC3\xB6",
5295 'Ouml;' => "\xC3\x96",
5296 'ouml;' => "\xC3\xB6",
5297 'para' => "\xC2\xB6",
5298 'para;' => "\xC2\xB6",
5299 'part;' => "\xE2\x88\x82",
5300 'permil;' => "\xE2\x80\xB0",
5301 'perp;' => "\xE2\x8A\xA5",
5302 'Phi;' => "\xCE\xA6",
5303 'phi;' => "\xCF\x86",
5304 'Pi;' => "\xCE\xA0",
5305 'pi;' => "\xCF\x80",
5306 'piv;' => "\xCF\x96",
5307 'plusmn' => "\xC2\xB1",
5308 'plusmn;' => "\xC2\xB1",
5309 'pound' => "\xC2\xA3",
5310 'pound;' => "\xC2\xA3",
5311 'Prime;' => "\xE2\x80\xB3",
5312 'prime;' => "\xE2\x80\xB2",
5313 'prod;' => "\xE2\x88\x8F",
5314 'prop;' => "\xE2\x88\x9D",
5315 'Psi;' => "\xCE\xA8",
5316 'psi;' => "\xCF\x88",
5317 'QUOT' => "\x22",
5318 'quot' => "\x22",
5319 'QUOT;' => "\x22",
5320 'quot;' => "\x22",
5321 'radic;' => "\xE2\x88\x9A",
5322 'rang;' => "\xE3\x80\x89",
5323 'raquo' => "\xC2\xBB",
5324 'raquo;' => "\xC2\xBB",
5325 'rArr;' => "\xE2\x87\x92",
5326 'rarr;' => "\xE2\x86\x92",
5327 'rceil;' => "\xE2\x8C\x89",
5328 'rdquo;' => "\xE2\x80\x9D",
5329 'real;' => "\xE2\x84\x9C",
5330 'REG' => "\xC2\xAE",
5331 'reg' => "\xC2\xAE",
5332 'REG;' => "\xC2\xAE",
5333 'reg;' => "\xC2\xAE",
5334 'rfloor;' => "\xE2\x8C\x8B",
5335 'Rho;' => "\xCE\xA1",
5336 'rho;' => "\xCF\x81",
5337 'rlm;' => "\xE2\x80\x8F",
5338 'rsaquo;' => "\xE2\x80\xBA",
5339 'rsquo;' => "\xE2\x80\x99",
5340 'sbquo;' => "\xE2\x80\x9A",
5341 'Scaron;' => "\xC5\xA0",
5342 'scaron;' => "\xC5\xA1",
5343 'sdot;' => "\xE2\x8B\x85",
5344 'sect' => "\xC2\xA7",
5345 'sect;' => "\xC2\xA7",
5346 'shy' => "\xC2\xAD",
5347 'shy;' => "\xC2\xAD",
5348 'Sigma;' => "\xCE\xA3",
5349 'sigma;' => "\xCF\x83",
5350 'sigmaf;' => "\xCF\x82",
5351 'sim;' => "\xE2\x88\xBC",
5352 'spades;' => "\xE2\x99\xA0",
5353 'sub;' => "\xE2\x8A\x82",
5354 'sube;' => "\xE2\x8A\x86",
5355 'sum;' => "\xE2\x88\x91",
5356 'sup;' => "\xE2\x8A\x83",
5357 'sup1' => "\xC2\xB9",
5358 'sup1;' => "\xC2\xB9",
5359 'sup2' => "\xC2\xB2",
5360 'sup2;' => "\xC2\xB2",
5361 'sup3' => "\xC2\xB3",
5362 'sup3;' => "\xC2\xB3",
5363 'supe;' => "\xE2\x8A\x87",
5364 'szlig' => "\xC3\x9F",
5365 'szlig;' => "\xC3\x9F",
5366 'Tau;' => "\xCE\xA4",
5367 'tau;' => "\xCF\x84",
5368 'there4;' => "\xE2\x88\xB4",
5369 'Theta;' => "\xCE\x98",
5370 'theta;' => "\xCE\xB8",
5371 'thetasym;' => "\xCF\x91",
5372 'thinsp;' => "\xE2\x80\x89",
5373 'THORN' => "\xC3\x9E",
5374 'thorn' => "\xC3\xBE",
5375 'THORN;' => "\xC3\x9E",
5376 'thorn;' => "\xC3\xBE",
5377 'tilde;' => "\xCB\x9C",
5378 'times' => "\xC3\x97",
5379 'times;' => "\xC3\x97",
5380 'TRADE;' => "\xE2\x84\xA2",
5381 'trade;' => "\xE2\x84\xA2",
5382 'Uacute' => "\xC3\x9A",
5383 'uacute' => "\xC3\xBA",
5384 'Uacute;' => "\xC3\x9A",
5385 'uacute;' => "\xC3\xBA",
5386 'uArr;' => "\xE2\x87\x91",
5387 'uarr;' => "\xE2\x86\x91",
5388 'Ucirc' => "\xC3\x9B",
5389 'ucirc' => "\xC3\xBB",
5390 'Ucirc;' => "\xC3\x9B",
5391 'ucirc;' => "\xC3\xBB",
5392 'Ugrave' => "\xC3\x99",
5393 'ugrave' => "\xC3\xB9",
5394 'Ugrave;' => "\xC3\x99",
5395 'ugrave;' => "\xC3\xB9",
5396 'uml' => "\xC2\xA8",
5397 'uml;' => "\xC2\xA8",
5398 'upsih;' => "\xCF\x92",
5399 'Upsilon;' => "\xCE\xA5",
5400 'upsilon;' => "\xCF\x85",
5401 'Uuml' => "\xC3\x9C",
5402 'uuml' => "\xC3\xBC",
5403 'Uuml;' => "\xC3\x9C",
5404 'uuml;' => "\xC3\xBC",
5405 'weierp;' => "\xE2\x84\x98",
5406 'Xi;' => "\xCE\x9E",
5407 'xi;' => "\xCE\xBE",
5408 'Yacute' => "\xC3\x9D",
5409 'yacute' => "\xC3\xBD",
5410 'Yacute;' => "\xC3\x9D",
5411 'yacute;' => "\xC3\xBD",
5412 'yen' => "\xC2\xA5",
5413 'yen;' => "\xC2\xA5",
5414 'yuml' => "\xC3\xBF",
5415 'Yuml;' => "\xC5\xB8",
5416 'yuml;' => "\xC3\xBF",
5417 'Zeta;' => "\xCE\x96",
5418 'zeta;' => "\xCE\xB6",
5419 'zwj;' => "\xE2\x80\x8D",
5420 'zwnj;' => "\xE2\x80\x8C"
5421 );
f2f7b699 5422
a6e043ff
AD
5423 for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
5424 {
5425 $consumed = substr($this->consumed, 1);
5426 if (isset($entities[$consumed]))
5427 {
5428 $match = $consumed;
5429 }
5430 }
f2f7b699 5431
a6e043ff
AD
5432 if ($match !== null)
5433 {
5434 $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
5435 $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
5436 }
5437 break;
5438 }
5439 }
5440}
f2f7b699 5441
a6e043ff
AD
5442/**
5443 * Handles everything related to enclosures (including Media RSS and iTunes RSS)
5444 *
5445 * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
5446 *
5447 * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
5448 *
5449 * @package SimplePie
5450 * @subpackage API
5451 */
5452class SimplePie_Enclosure
5453{
5454 /**
5455 * @var string
5456 * @see get_bitrate()
5457 */
5458 var $bitrate;
f2f7b699 5459
a6e043ff
AD
5460 /**
5461 * @var array
5462 * @see get_captions()
5463 */
5464 var $captions;
f2f7b699 5465
a6e043ff
AD
5466 /**
5467 * @var array
5468 * @see get_categories()
5469 */
5470 var $categories;
f2f7b699 5471
a6e043ff
AD
5472 /**
5473 * @var int
5474 * @see get_channels()
5475 */
5476 var $channels;
f2f7b699 5477
a6e043ff
AD
5478 /**
5479 * @var SimplePie_Copyright
5480 * @see get_copyright()
5481 */
5482 var $copyright;
f2f7b699 5483
a6e043ff
AD
5484 /**
5485 * @var array
5486 * @see get_credits()
5487 */
5488 var $credits;
f2f7b699 5489
a6e043ff
AD
5490 /**
5491 * @var string
5492 * @see get_description()
5493 */
5494 var $description;
f2f7b699 5495
a6e043ff
AD
5496 /**
5497 * @var int
5498 * @see get_duration()
5499 */
5500 var $duration;
f2f7b699 5501
a6e043ff
AD
5502 /**
5503 * @var string
5504 * @see get_expression()
5505 */
5506 var $expression;
f2f7b699 5507
a6e043ff
AD
5508 /**
5509 * @var string
5510 * @see get_framerate()
5511 */
5512 var $framerate;
f2f7b699 5513
a6e043ff
AD
5514 /**
5515 * @var string
5516 * @see get_handler()
5517 */
5518 var $handler;
f2f7b699 5519
a6e043ff
AD
5520 /**
5521 * @var array
5522 * @see get_hashes()
5523 */
5524 var $hashes;
f2f7b699 5525
a6e043ff
AD
5526 /**
5527 * @var string
5528 * @see get_height()
5529 */
5530 var $height;
f2f7b699 5531
a6e043ff
AD
5532 /**
5533 * @deprecated
5534 * @var null
5535 */
5536 var $javascript;
f2f7b699 5537
a6e043ff
AD
5538 /**
5539 * @var array
5540 * @see get_keywords()
5541 */
5542 var $keywords;
f2f7b699 5543
a6e043ff
AD
5544 /**
5545 * @var string
5546 * @see get_language()
5547 */
5548 var $lang;
f2f7b699 5549
a6e043ff
AD
5550 /**
5551 * @var string
5552 * @see get_length()
5553 */
5554 var $length;
f2f7b699 5555
a6e043ff
AD
5556 /**
5557 * @var string
5558 * @see get_link()
5559 */
5560 var $link;
6d7d21a0 5561
a6e043ff
AD
5562 /**
5563 * @var string
5564 * @see get_medium()
5565 */
5566 var $medium;
5567
5568 /**
5569 * @var string
5570 * @see get_player()
5571 */
5572 var $player;
5573
5574 /**
5575 * @var array
5576 * @see get_ratings()
5577 */
5578 var $ratings;
5579
5580 /**
5581 * @var array
5582 * @see get_restrictions()
5583 */
5584 var $restrictions;
5585
5586 /**
5587 * @var string
5588 * @see get_sampling_rate()
5589 */
5590 var $samplingrate;
5591
5592 /**
5593 * @var array
5594 * @see get_thumbnails()
5595 */
5596 var $thumbnails;
5597
5598 /**
5599 * @var string
5600 * @see get_title()
5601 */
5602 var $title;
5603
5604 /**
5605 * @var string
5606 * @see get_type()
5607 */
5608 var $type;
5609
5610 /**
5611 * @var string
5612 * @see get_width()
5613 */
5614 var $width;
6d7d21a0 5615
a6e043ff
AD
5616 /**
5617 * Constructor, used to input the data
5618 *
5619 * For documentation on all the parameters, see the corresponding
5620 * properties and their accessors
5621 *
5622 * @uses idna_convert If available, this will convert an IDN
5623 */
5624 public function __construct($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
5625 {
5626 $this->bitrate = $bitrate;
5627 $this->captions = $captions;
5628 $this->categories = $categories;
5629 $this->channels = $channels;
5630 $this->copyright = $copyright;
5631 $this->credits = $credits;
5632 $this->description = $description;
5633 $this->duration = $duration;
5634 $this->expression = $expression;
5635 $this->framerate = $framerate;
5636 $this->hashes = $hashes;
5637 $this->height = $height;
5638 $this->keywords = $keywords;
5639 $this->lang = $lang;
5640 $this->length = $length;
5641 $this->link = $link;
5642 $this->medium = $medium;
5643 $this->player = $player;
5644 $this->ratings = $ratings;
5645 $this->restrictions = $restrictions;
5646 $this->samplingrate = $samplingrate;
5647 $this->thumbnails = $thumbnails;
5648 $this->title = $title;
5649 $this->type = $type;
5650 $this->width = $width;
5651
5652 if (class_exists('idna_convert'))
5653 {
5654 $idn = new idna_convert();
5655 $parsed = SimplePie_Misc::parse_url($link);
5656 $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
f2f7b699 5657 }
a6e043ff
AD
5658 $this->handler = $this->get_handler(); // Needs to load last
5659 }
5660
5661 /**
5662 * String-ified version
5663 *
5664 * @return string
5665 */
5666 public function __toString()
5667 {
5668 // There is no $this->data here
5669 return md5(serialize($this));
5670 }
5671
5672 /**
5673 * Get the bitrate
5674 *
5675 * @return string|null
5676 */
5677 public function get_bitrate()
5678 {
5679 if ($this->bitrate !== null)
f2f7b699 5680 {
a6e043ff 5681 return $this->bitrate;
f2f7b699
AD
5682 }
5683 else
5684 {
5685 return null;
5686 }
5687 }
5688
a6e043ff
AD
5689 /**
5690 * Get a single caption
5691 *
5692 * @param int $key
5693 * @return SimplePie_Caption|null
5694 */
5695 public function get_caption($key = 0)
f2f7b699 5696 {
a6e043ff
AD
5697 $captions = $this->get_captions();
5698 if (isset($captions[$key]))
f2f7b699 5699 {
a6e043ff 5700 return $captions[$key];
f2f7b699
AD
5701 }
5702 else
5703 {
5704 return null;
5705 }
5706 }
5707
a6e043ff
AD
5708 /**
5709 * Get all captions
5710 *
5711 * @return array|null Array of {@see SimplePie_Caption} objects
5712 */
5713 public function get_captions()
f2f7b699 5714 {
a6e043ff 5715 if ($this->captions !== null)
f2f7b699 5716 {
a6e043ff 5717 return $this->captions;
f2f7b699 5718 }
a6e043ff 5719 else
f2f7b699 5720 {
a6e043ff 5721 return null;
f2f7b699 5722 }
a6e043ff
AD
5723 }
5724
5725 /**
5726 * Get a single category
5727 *
5728 * @param int $key
5729 * @return SimplePie_Category|null
5730 */
5731 public function get_category($key = 0)
5732 {
5733 $categories = $this->get_categories();
5734 if (isset($categories[$key]))
f2f7b699 5735 {
a6e043ff 5736 return $categories[$key];
f2f7b699
AD
5737 }
5738 else
5739 {
5740 return null;
5741 }
5742 }
f954bd49 5743
a6e043ff
AD
5744 /**
5745 * Get all categories
5746 *
5747 * @return array|null Array of {@see SimplePie_Category} objects
5748 */
5749 public function get_categories()
6d7d21a0 5750 {
a6e043ff 5751 if ($this->categories !== null)
6d7d21a0 5752 {
a6e043ff 5753 return $this->categories;
6d7d21a0
AD
5754 }
5755 else
5756 {
5757 return null;
5758 }
5759 }
f2f7b699
AD
5760
5761 /**
a6e043ff 5762 * Get the number of audio channels
f2f7b699 5763 *
a6e043ff 5764 * @return int|null
f2f7b699 5765 */
a6e043ff 5766 public function get_channels()
f2f7b699 5767 {
a6e043ff 5768 if ($this->channels !== null)
f2f7b699 5769 {
a6e043ff 5770 return $this->channels;
f2f7b699
AD
5771 }
5772 else
5773 {
5774 return null;
5775 }
5776 }
5777
a6e043ff
AD
5778 /**
5779 * Get the copyright information
5780 *
5781 * @return SimplePie_Copyright|null
5782 */
5783 public function get_copyright()
f2f7b699 5784 {
a6e043ff
AD
5785 if ($this->copyright !== null)
5786 {
5787 return $this->copyright;
5788 }
5789 else
5790 {
5791 return null;
5792 }
f2f7b699
AD
5793 }
5794
a6e043ff
AD
5795 /**
5796 * Get a single credit
5797 *
5798 * @param int $key
5799 * @return SimplePie_Credit|null
5800 */
5801 public function get_credit($key = 0)
f2f7b699 5802 {
a6e043ff
AD
5803 $credits = $this->get_credits();
5804 if (isset($credits[$key]))
5805 {
5806 return $credits[$key];
5807 }
5808 else
5809 {
5810 return null;
5811 }
f2f7b699
AD
5812 }
5813
a6e043ff
AD
5814 /**
5815 * Get all credits
5816 *
5817 * @return array|null Array of {@see SimplePie_Credit} objects
5818 */
5819 public function get_credits()
f2f7b699 5820 {
a6e043ff
AD
5821 if ($this->credits !== null)
5822 {
5823 return $this->credits;
5824 }
5825 else
5826 {
5827 return null;
5828 }
f2f7b699
AD
5829 }
5830
a6e043ff
AD
5831 /**
5832 * Get the description of the enclosure
5833 *
5834 * @return string|null
5835 */
5836 public function get_description()
f2f7b699 5837 {
a6e043ff
AD
5838 if ($this->description !== null)
5839 {
5840 return $this->description;
5841 }
5842 else
5843 {
5844 return null;
5845 }
f2f7b699
AD
5846 }
5847
a6e043ff
AD
5848 /**
5849 * Get the duration of the enclosure
5850 *
5851 * @param string $convert Convert seconds into hh:mm:ss
5852 * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
5853 */
5854 public function get_duration($convert = false)
f2f7b699 5855 {
a6e043ff
AD
5856 if ($this->duration !== null)
5857 {
5858 if ($convert)
5859 {
5860 $time = SimplePie_Misc::time_hms($this->duration);
5861 return $time;
5862 }
5863 else
5864 {
5865 return $this->duration;
5866 }
5867 }
5868 else
5869 {
5870 return null;
5871 }
f2f7b699
AD
5872 }
5873
a6e043ff
AD
5874 /**
5875 * Get the expression
5876 *
5877 * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
5878 */
5879 public function get_expression()
f2f7b699 5880 {
a6e043ff
AD
5881 if ($this->expression !== null)
5882 {
5883 return $this->expression;
5884 }
5885 else
5886 {
5887 return 'full';
5888 }
f2f7b699
AD
5889 }
5890
a6e043ff
AD
5891 /**
5892 * Get the file extension
5893 *
5894 * @return string|null
5895 */
5896 public function get_extension()
f2f7b699 5897 {
a6e043ff
AD
5898 if ($this->link !== null)
5899 {
5900 $url = SimplePie_Misc::parse_url($this->link);
5901 if ($url['path'] !== '')
5902 {
5903 return pathinfo($url['path'], PATHINFO_EXTENSION);
5904 }
5905 }
5906 return null;
f2f7b699
AD
5907 }
5908
a6e043ff
AD
5909 /**
5910 * Get the framerate (in frames-per-second)
5911 *
5912 * @return string|null
5913 */
5914 public function get_framerate()
f2f7b699 5915 {
a6e043ff
AD
5916 if ($this->framerate !== null)
5917 {
5918 return $this->framerate;
5919 }
5920 else
5921 {
5922 return null;
5923 }
f2f7b699 5924 }
f2f7b699 5925
a6e043ff
AD
5926 /**
5927 * Get the preferred handler
5928 *
5929 * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
5930 */
5931 public function get_handler()
f2f7b699 5932 {
a6e043ff 5933 return $this->get_real_type(true);
f2f7b699
AD
5934 }
5935
a6e043ff
AD
5936 /**
5937 * Get a single hash
5938 *
5939 * @link http://www.rssboard.org/media-rss#media-hash
5940 * @param int $key
5941 * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
5942 */
5943 public function get_hash($key = 0)
f2f7b699 5944 {
a6e043ff
AD
5945 $hashes = $this->get_hashes();
5946 if (isset($hashes[$key]))
5947 {
5948 return $hashes[$key];
5949 }
5950 else
5951 {
5952 return null;
5953 }
f2f7b699 5954 }
f954bd49 5955
a6e043ff
AD
5956 /**
5957 * Get all credits
5958 *
5959 * @return array|null Array of strings, see {@see get_hash()}
5960 */
5961 public function get_hashes()
f2f7b699 5962 {
a6e043ff 5963 if ($this->hashes !== null)
f2f7b699 5964 {
a6e043ff 5965 return $this->hashes;
f2f7b699
AD
5966 }
5967 else
5968 {
5969 return null;
5970 }
5971 }
5972
a6e043ff
AD
5973 /**
5974 * Get the height
5975 *
5976 * @return string|null
5977 */
5978 public function get_height()
f2f7b699 5979 {
a6e043ff
AD
5980 if ($this->height !== null)
5981 {
5982 return $this->height;
5983 }
5984 else
5985 {
5986 return null;
5987 }
f2f7b699 5988 }
f2f7b699 5989
a6e043ff
AD
5990 /**
5991 * Get the language
5992 *
5993 * @link http://tools.ietf.org/html/rfc3066
5994 * @return string|null Language code as per RFC 3066
5995 */
5996 public function get_language()
f2f7b699 5997 {
a6e043ff
AD
5998 if ($this->lang !== null)
5999 {
6000 return $this->lang;
6001 }
6002 else
6003 {
6004 return null;
6005 }
f2f7b699
AD
6006 }
6007
a6e043ff
AD
6008 /**
6009 * Get a single keyword
6010 *
6011 * @param int $key
6012 * @return string|null
6013 */
6014 public function get_keyword($key = 0)
f2f7b699 6015 {
a6e043ff
AD
6016 $keywords = $this->get_keywords();
6017 if (isset($keywords[$key]))
6018 {
6019 return $keywords[$key];
6020 }
6021 else
6022 {
6023 return null;
6024 }
f2f7b699
AD
6025 }
6026
a6e043ff
AD
6027 /**
6028 * Get all keywords
6029 *
6030 * @return array|null Array of strings
6031 */
6032 public function get_keywords()
f2f7b699 6033 {
a6e043ff 6034 if ($this->keywords !== null)
f2f7b699 6035 {
a6e043ff 6036 return $this->keywords;
6d7d21a0 6037 }
a6e043ff 6038 else
6d7d21a0 6039 {
a6e043ff 6040 return null;
6d7d21a0 6041 }
a6e043ff
AD
6042 }
6043
6044 /**
6045 * Get length
6046 *
6047 * @return float Length in bytes
6048 */
6049 public function get_length()
6050 {
6051 if ($this->length !== null)
6d7d21a0 6052 {
a6e043ff 6053 return $this->length;
6d7d21a0 6054 }
a6e043ff 6055 else
6d7d21a0 6056 {
a6e043ff 6057 return null;
6d7d21a0 6058 }
a6e043ff
AD
6059 }
6060
6061 /**
6062 * Get the URL
6063 *
6064 * @return string|null
6065 */
6066 public function get_link()
6067 {
6068 if ($this->link !== null)
6d7d21a0 6069 {
a6e043ff 6070 return urldecode($this->link);
6d7d21a0 6071 }
a6e043ff 6072 else
6d7d21a0 6073 {
a6e043ff 6074 return null;
6d7d21a0 6075 }
a6e043ff
AD
6076 }
6077
6078 /**
6079 * Get the medium
6080 *
6081 * @link http://www.rssboard.org/media-rss#media-content
6082 * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
6083 */
6084 public function get_medium()
6085 {
6086 if ($this->medium !== null)
6d7d21a0 6087 {
a6e043ff 6088 return $this->medium;
f2f7b699
AD
6089 }
6090 else
6091 {
6092 return null;
6093 }
6094 }
6095
a6e043ff
AD
6096 /**
6097 * Get the player URL
6098 *
6099 * Typically the same as {@see get_permalink()}
6100 * @return string|null Player URL
6101 */
6102 public function get_player()
f2f7b699 6103 {
a6e043ff 6104 if ($this->player !== null)
f2f7b699 6105 {
a6e043ff 6106 return $this->player;
f2f7b699
AD
6107 }
6108 else
6109 {
6110 return null;
6111 }
6112 }
6113
a6e043ff
AD
6114 /**
6115 * Get a single rating
6116 *
6117 * @param int $key
6118 * @return SimplePie_Rating|null
6119 */
6120 public function get_rating($key = 0)
f2f7b699 6121 {
a6e043ff
AD
6122 $ratings = $this->get_ratings();
6123 if (isset($ratings[$key]))
f2f7b699 6124 {
a6e043ff 6125 return $ratings[$key];
f2f7b699 6126 }
a6e043ff 6127 else
f2f7b699 6128 {
a6e043ff 6129 return null;
6d7d21a0 6130 }
a6e043ff
AD
6131 }
6132
6133 /**
6134 * Get all ratings
6135 *
6136 * @return array|null Array of {@see SimplePie_Rating} objects
6137 */
6138 public function get_ratings()
6139 {
6140 if ($this->ratings !== null)
6d7d21a0 6141 {
a6e043ff 6142 return $this->ratings;
6d7d21a0 6143 }
a6e043ff 6144 else
6d7d21a0 6145 {
a6e043ff 6146 return null;
f2f7b699 6147 }
a6e043ff 6148 }
f2f7b699 6149
a6e043ff
AD
6150 /**
6151 * Get a single restriction
6152 *
6153 * @param int $key
6154 * @return SimplePie_Restriction|null
6155 */
6156 public function get_restriction($key = 0)
6157 {
6158 $restrictions = $this->get_restrictions();
6159 if (isset($restrictions[$key]))
f2f7b699 6160 {
a6e043ff 6161 return $restrictions[$key];
f2f7b699
AD
6162 }
6163 else
6164 {
6165 return null;
6166 }
6167 }
6168
a6e043ff
AD
6169 /**
6170 * Get all restrictions
6171 *
6172 * @return array|null Array of {@see SimplePie_Restriction} objects
6173 */
6174 public function get_restrictions()
f2f7b699 6175 {
a6e043ff 6176 if ($this->restrictions !== null)
f2f7b699 6177 {
a6e043ff 6178 return $this->restrictions;
f2f7b699
AD
6179 }
6180 else
6181 {
6182 return null;
6183 }
6184 }
6185
a6e043ff
AD
6186 /**
6187 * Get the sampling rate (in kHz)
6188 *
6189 * @return string|null
6190 */
6191 public function get_sampling_rate()
f2f7b699 6192 {
a6e043ff 6193 if ($this->samplingrate !== null)
f2f7b699 6194 {
a6e043ff 6195 return $this->samplingrate;
f2f7b699 6196 }
a6e043ff 6197 else
f2f7b699 6198 {
a6e043ff 6199 return null;
f2f7b699 6200 }
a6e043ff
AD
6201 }
6202
6203 /**
6204 * Get the file size (in MiB)
6205 *
6206 * @return float|null File size in mebibytes (1048 bytes)
6207 */
6208 public function get_size()
6209 {
6210 $length = $this->get_length();
6211 if ($length !== null)
f2f7b699 6212 {
a6e043ff 6213 return round($length/1048576, 2);
6d7d21a0 6214 }
a6e043ff 6215 else
6d7d21a0 6216 {
a6e043ff 6217 return null;
f2f7b699 6218 }
a6e043ff 6219 }
f2f7b699 6220
a6e043ff
AD
6221 /**
6222 * Get a single thumbnail
6223 *
6224 * @param int $key
6225 * @return string|null Thumbnail URL
6226 */
6227 public function get_thumbnail($key = 0)
6228 {
6229 $thumbnails = $this->get_thumbnails();
6230 if (isset($thumbnails[$key]))
f2f7b699 6231 {
a6e043ff 6232 return $thumbnails[$key];
f2f7b699
AD
6233 }
6234 else
6235 {
6236 return null;
6237 }
6238 }
6239
a6e043ff
AD
6240 /**
6241 * Get all thumbnails
6242 *
6243 * @return array|null Array of thumbnail URLs
6244 */
6245 public function get_thumbnails()
f2f7b699 6246 {
a6e043ff 6247 if ($this->thumbnails !== null)
f2f7b699 6248 {
a6e043ff 6249 return $this->thumbnails;
f2f7b699
AD
6250 }
6251 else
6252 {
6253 return null;
6254 }
6255 }
6256
a6e043ff
AD
6257 /**
6258 * Get the title
6259 *
6260 * @return string|null
6261 */
6262 public function get_title()
f2f7b699 6263 {
a6e043ff 6264 if ($this->title !== null)
f2f7b699 6265 {
a6e043ff 6266 return $this->title;
f2f7b699 6267 }
a6e043ff 6268 else
f2f7b699 6269 {
a6e043ff 6270 return null;
f2f7b699 6271 }
a6e043ff 6272 }
f2f7b699 6273
a6e043ff
AD
6274 /**
6275 * Get mimetype of the enclosure
6276 *
6277 * @see get_real_type()
6278 * @return string|null MIME type
6279 */
6280 public function get_type()
6281 {
6282 if ($this->type !== null)
f2f7b699 6283 {
a6e043ff 6284 return $this->type;
f2f7b699
AD
6285 }
6286 else
6287 {
6288 return null;
6289 }
6290 }
6291
a6e043ff
AD
6292 /**
6293 * Get the width
6294 *
6295 * @return string|null
6296 */
6297 public function get_width()
f2f7b699 6298 {
a6e043ff 6299 if ($this->width !== null)
f2f7b699 6300 {
a6e043ff 6301 return $this->width;
f2f7b699
AD
6302 }
6303 else
6304 {
6305 return null;
6306 }
6307 }
6308
6d7d21a0 6309 /**
a6e043ff
AD
6310 * Embed the enclosure using `<embed>`
6311 *
6312 * @deprecated Use the second parameter to {@see embed} instead
6313 *
6314 * @param array|string $options See first paramter to {@see embed}
6315 * @return string HTML string to output
6d7d21a0 6316 */
a6e043ff 6317 public function native_embed($options='')
f2f7b699 6318 {
a6e043ff 6319 return $this->embed($options, true);
f2f7b699
AD
6320 }
6321
a6e043ff
AD
6322 /**
6323 * Embed the enclosure using Javascript
6324 *
6325 * `$options` is an array or comma-separated key:value string, with the
6326 * following properties:
6327 *
6328 * - `alt` (string): Alternate content for when an end-user does not have
6329 * the appropriate handler installed or when a file type is
6330 * unsupported. Can be any text or HTML. Defaults to blank.
6331 * - `altclass` (string): If a file type is unsupported, the end-user will
6332 * see the alt text (above) linked directly to the content. That link
6333 * will have this value as its class name. Defaults to blank.
6334 * - `audio` (string): This is an image that should be used as a
6335 * placeholder for audio files before they're loaded (QuickTime-only).
6336 * Can be any relative or absolute URL. Defaults to blank.
6337 * - `bgcolor` (string): The background color for the media, if not
6338 * already transparent. Defaults to `#ffffff`.
6339 * - `height` (integer): The height of the embedded media. Accepts any
6340 * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
6341 * and it is recommended that you use this default.
6342 * - `loop` (boolean): Do you want the media to loop when its done?
6343 * Defaults to `false`.
6344 * - `mediaplayer` (string): The location of the included
6345 * `mediaplayer.swf` file. This allows for the playback of Flash Video
6346 * (`.flv`) files, and is the default handler for non-Odeo MP3's.
6347 * Defaults to blank.
6348 * - `video` (string): This is an image that should be used as a
6349 * placeholder for video files before they're loaded (QuickTime-only).
6350 * Can be any relative or absolute URL. Defaults to blank.
6351 * - `width` (integer): The width of the embedded media. Accepts any
6352 * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
6353 * and it is recommended that you use this default.
6354 * - `widescreen` (boolean): Is the enclosure widescreen or standard?
6355 * This applies only to video enclosures, and will automatically resize
6356 * the content appropriately. Defaults to `false`, implying 4:3 mode.
6357 *
6358 * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
6359 * will default to 480x360 video resolution. Widescreen (16:9) mode with
6360 * `width` and `height` set to `auto` will default to 480x270 video resolution.
6361 *
6362 * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
6363 * @param array|string $options Comma-separated key:value list, or array
6364 * @param bool $native Use `<embed>`
6365 * @return string HTML string to output
6366 */
6367 public function embed($options = '', $native = false)
f2f7b699 6368 {
a6e043ff
AD
6369 // Set up defaults
6370 $audio = '';
6371 $video = '';
6372 $alt = '';
6373 $altclass = '';
6374 $loop = 'false';
6375 $width = 'auto';
6376 $height = 'auto';
6377 $bgcolor = '#ffffff';
6378 $mediaplayer = '';
6379 $widescreen = false;
6380 $handler = $this->get_handler();
6381 $type = $this->get_real_type();
6382
6383 // Process options and reassign values as necessary
6384 if (is_array($options))
f2f7b699 6385 {
a6e043ff
AD
6386 extract($options);
6387 }
6388 else
6389 {
6390 $options = explode(',', $options);
6391 foreach($options as $option)
f2f7b699 6392 {
a6e043ff
AD
6393 $opt = explode(':', $option, 2);
6394 if (isset($opt[0], $opt[1]))
6d7d21a0 6395 {
a6e043ff
AD
6396 $opt[0] = trim($opt[0]);
6397 $opt[1] = trim($opt[1]);
6398 switch ($opt[0])
6d7d21a0 6399 {
a6e043ff
AD
6400 case 'audio':
6401 $audio = $opt[1];
6402 break;
6403
6404 case 'video':
6405 $video = $opt[1];
6406 break;
6407
6408 case 'alt':
6409 $alt = $opt[1];
6410 break;
6411
6412 case 'altclass':
6413 $altclass = $opt[1];
6414 break;
6415
6416 case 'loop':
6417 $loop = $opt[1];
6418 break;
6419
6420 case 'width':
6421 $width = $opt[1];
6422 break;
6423
6424 case 'height':
6425 $height = $opt[1];
6426 break;
6427
6428 case 'bgcolor':
6429 $bgcolor = $opt[1];
6430 break;
6431
6432 case 'mediaplayer':
6433 $mediaplayer = $opt[1];
6434 break;
6435
6436 case 'widescreen':
6437 $widescreen = $opt[1];
6438 break;
6d7d21a0
AD
6439 }
6440 }
f2f7b699 6441 }
a6e043ff
AD
6442 }
6443
6444 $mime = explode('/', $type, 2);
6445 $mime = $mime[0];
6446
6447 // Process values for 'auto'
6448 if ($width === 'auto')
6449 {
6450 if ($mime === 'video')
f2f7b699 6451 {
a6e043ff 6452 if ($height === 'auto')
6d7d21a0 6453 {
a6e043ff
AD
6454 $width = 480;
6455 }
6456 elseif ($widescreen)
6457 {
6458 $width = round((intval($height)/9)*16);
6459 }
6460 else
6461 {
6462 $width = round((intval($height)/3)*4);
6d7d21a0
AD
6463 }
6464 }
a6e043ff 6465 else
f2f7b699 6466 {
a6e043ff 6467 $width = '100%';
6d7d21a0 6468 }
a6e043ff
AD
6469 }
6470
6471 if ($height === 'auto')
6472 {
6473 if ($mime === 'audio')
6d7d21a0 6474 {
a6e043ff 6475 $height = 0;
6d7d21a0 6476 }
a6e043ff 6477 elseif ($mime === 'video')
6d7d21a0 6478 {
a6e043ff 6479 if ($width === 'auto')
6d7d21a0 6480 {
a6e043ff 6481 if ($widescreen)
6d7d21a0 6482 {
a6e043ff 6483 $height = 270;
6d7d21a0
AD
6484 }
6485 else
6486 {
a6e043ff 6487 $height = 360;
6d7d21a0
AD
6488 }
6489 }
a6e043ff 6490 elseif ($widescreen)
6d7d21a0 6491 {
a6e043ff
AD
6492 $height = round((intval($width)/16)*9);
6493 }
6494 else
6495 {
6496 $height = round((intval($width)/4)*3);
6d7d21a0 6497 }
a6e043ff
AD
6498 }
6499 else
6500 {
6501 $height = 376;
f2f7b699
AD
6502 }
6503 }
a6e043ff 6504 elseif ($mime === 'audio')
f2f7b699 6505 {
a6e043ff 6506 $height = 0;
f2f7b699 6507 }
f2f7b699 6508
a6e043ff
AD
6509 // Set proper placeholder value
6510 if ($mime === 'audio')
f2f7b699 6511 {
a6e043ff 6512 $placeholder = $audio;
f2f7b699 6513 }
a6e043ff 6514 elseif ($mime === 'video')
f2f7b699 6515 {
a6e043ff 6516 $placeholder = $video;
f2f7b699 6517 }
f2f7b699 6518
a6e043ff 6519 $embed = '';
f2f7b699 6520
a6e043ff
AD
6521 // Flash
6522 if ($handler === 'flash')
f2f7b699 6523 {
a6e043ff
AD
6524 if ($native)
6525 {
6526 $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
6527 }
6528 else
6529 {
6530 $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
6531 }
f2f7b699 6532 }
f2f7b699 6533
a6e043ff
AD
6534 // Flash Media Player file types.
6535 // Preferred handler for MP3 file types.
6536 elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
f2f7b699 6537 {
a6e043ff
AD
6538 $height += 20;
6539 if ($native)
6540 {
6541 $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
6542 }
6543 else
6544 {
6545 $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
6546 }
f2f7b699 6547 }
f2f7b699 6548
a6e043ff
AD
6549 // QuickTime 7 file types. Need to test with QuickTime 6.
6550 // Only handle MP3's if the Flash Media Player is not present.
6551 elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
f2f7b699 6552 {
a6e043ff
AD
6553 $height += 16;
6554 if ($native)
6555 {
6556 if ($placeholder !== '')
6557 {
6558 $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
6559 }
6560 else
6561 {
6562 $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
6563 }
6564 }
6565 else
6566 {
6567 $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
6568 }
f2f7b699 6569 }
f2f7b699 6570
a6e043ff
AD
6571 // Windows Media
6572 elseif ($handler === 'wmedia')
f2f7b699 6573 {
a6e043ff
AD
6574 $height += 45;
6575 if ($native)
6576 {
6577 $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
6578 }
6579 else
6580 {
6581 $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
6582 }
f2f7b699 6583 }
f2f7b699 6584
a6e043ff
AD
6585 // Everything else
6586 else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
6d7d21a0 6587
a6e043ff 6588 return $embed;
6d7d21a0
AD
6589 }
6590
a6e043ff
AD
6591 /**
6592 * Get the real media type
6593 *
6594 * Often, feeds lie to us, necessitating a bit of deeper inspection. This
6595 * converts types to their canonical representations based on the file
6596 * extension
6597 *
6598 * @see get_type()
6599 * @param bool $find_handler Internal use only, use {@see get_handler()} instead
6600 * @return string MIME type
6601 */
6602 public function get_real_type($find_handler = false)
6d7d21a0 6603 {
a6e043ff
AD
6604 // Mime-types by handler.
6605 $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
6606 $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
6607 $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
6608 $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
6609 $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
6d7d21a0 6610
a6e043ff 6611 if ($this->get_type() !== null)
f2f7b699 6612 {
a6e043ff 6613 $type = strtolower($this->type);
f2f7b699
AD
6614 }
6615 else
6616 {
a6e043ff 6617 $type = null;
f2f7b699 6618 }
f2f7b699 6619
a6e043ff
AD
6620 // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
6621 if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
f2f7b699 6622 {
a6e043ff
AD
6623 switch (strtolower($this->get_extension()))
6624 {
6625 // Audio mime-types
6626 case 'aac':
6627 case 'adts':
6628 $type = 'audio/acc';
6629 break;
f2f7b699 6630
a6e043ff
AD
6631 case 'aif':
6632 case 'aifc':
6633 case 'aiff':
6634 case 'cdda':
6635 $type = 'audio/aiff';
6636 break;
f2f7b699 6637
a6e043ff
AD
6638 case 'bwf':
6639 $type = 'audio/wav';
6640 break;
6d7d21a0 6641
a6e043ff
AD
6642 case 'kar':
6643 case 'mid':
6644 case 'midi':
6645 case 'smf':
6646 $type = 'audio/midi';
6647 break;
6d7d21a0 6648
a6e043ff
AD
6649 case 'm4a':
6650 $type = 'audio/x-m4a';
6651 break;
6d7d21a0 6652
a6e043ff
AD
6653 case 'mp3':
6654 case 'swa':
6655 $type = 'audio/mp3';
6656 break;
f2f7b699 6657
a6e043ff
AD
6658 case 'wav':
6659 $type = 'audio/wav';
6660 break;
6661
6662 case 'wax':
6663 $type = 'audio/x-ms-wax';
6664 break;
6665
6666 case 'wma':
6667 $type = 'audio/x-ms-wma';
6668 break;
6669
6670 // Video mime-types
6671 case '3gp':
6672 case '3gpp':
6673 $type = 'video/3gpp';
6674 break;
6675
6676 case '3g2':
6677 case '3gp2':
6678 $type = 'video/3gpp2';
6679 break;
6680
6681 case 'asf':
6682 $type = 'video/x-ms-asf';
6683 break;
6684
6685 case 'flv':
6686 $type = 'video/x-flv';
6687 break;
6688
6689 case 'm1a':
6690 case 'm1s':
6691 case 'm1v':
6692 case 'm15':
6693 case 'm75':
6694 case 'mp2':
6695 case 'mpa':
6696 case 'mpeg':
6697 case 'mpg':
6698 case 'mpm':
6699 case 'mpv':
6700 $type = 'video/mpeg';
6701 break;
6702
6703 case 'm4v':
6704 $type = 'video/x-m4v';
6705 break;
6706
6707 case 'mov':
6708 case 'qt':
6709 $type = 'video/quicktime';
6710 break;
6711
6712 case 'mp4':
6713 case 'mpg4':
6714 $type = 'video/mp4';
6715 break;
6716
6717 case 'sdv':
6718 $type = 'video/sd-video';
6719 break;
6720
6721 case 'wm':
6722 $type = 'video/x-ms-wm';
6723 break;
6724
6725 case 'wmv':
6726 $type = 'video/x-ms-wmv';
6727 break;
6728
6729 case 'wvx':
6730 $type = 'video/x-ms-wvx';
6731 break;
6732
6733 // Flash mime-types
6734 case 'spl':
6735 $type = 'application/futuresplash';
6736 break;
6737
6738 case 'swf':
6739 $type = 'application/x-shockwave-flash';
6740 break;
6741 }
f2f7b699 6742 }
f2f7b699 6743
a6e043ff 6744 if ($find_handler)
f2f7b699 6745 {
a6e043ff
AD
6746 if (in_array($type, $types_flash))
6747 {
6748 return 'flash';
6749 }
6750 elseif (in_array($type, $types_fmedia))
6751 {
6752 return 'fmedia';
6753 }
6754 elseif (in_array($type, $types_quicktime))
6755 {
6756 return 'quicktime';
6757 }
6758 elseif (in_array($type, $types_wmedia))
6759 {
6760 return 'wmedia';
6761 }
6762 elseif (in_array($type, $types_mp3))
6763 {
6764 return 'mp3';
6765 }
6766 else
6767 {
6768 return null;
6769 }
f2f7b699
AD
6770 }
6771 else
6772 {
a6e043ff 6773 return $type;
f2f7b699
AD
6774 }
6775 }
6d7d21a0 6776}
f2f7b699 6777
a6e043ff
AD
6778/**
6779 * General SimplePie exception class
6780 *
6781 * @package SimplePie
6782 */
6783class SimplePie_Exception extends Exception
6d7d21a0 6784{
a6e043ff
AD
6785}
6786
6787/**
6788 * Used for fetching remote files and reading local files
6789 *
6790 * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
6791 *
6792 * This class can be overloaded with {@see SimplePie::set_file_class()}
6793 *
6794 * @package SimplePie
6795 * @subpackage HTTP
6796 * @todo Move to properly supporting RFC2616 (HTTP/1.1)
6797 */
6798class SimplePie_File
6799{
6800 var $url;
6801 var $useragent;
6802 var $success = true;
6803 var $headers = array();
6804 var $body;
6805 var $status_code;
6806 var $redirects = 0;
6807 var $error;
6808 var $method = SIMPLEPIE_FILE_SOURCE_NONE;
6d7d21a0 6809
a6e043ff 6810 public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
f2f7b699 6811 {
6d7d21a0
AD
6812 if (class_exists('idna_convert'))
6813 {
a6e043ff
AD
6814 $idn = new idna_convert();
6815 $parsed = SimplePie_Misc::parse_url($url);
6816 $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
6d7d21a0 6817 }
a6e043ff
AD
6818 $this->url = $url;
6819 $this->useragent = $useragent;
6820 if (preg_match('/^http(s)?:\/\//i', $url))
6821 {
6822 if ($useragent === null)
6823 {
6824 $useragent = ini_get('user_agent');
6825 $this->useragent = $useragent;
6826 }
6827 if (!is_array($headers))
6828 {
6829 $headers = array();
6830 }
6831 if (!$force_fsockopen && function_exists('curl_exec'))
6832 {
6833 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
6834 $fp = curl_init();
6835 $headers2 = array();
6836 foreach ($headers as $key => $value)
6837 {
6838 $headers2[] = "$key: $value";
6839 }
6840 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
6841 {
6842 curl_setopt($fp, CURLOPT_ENCODING, '');
6843 }
6844 curl_setopt($fp, CURLOPT_URL, $url);
6845 curl_setopt($fp, CURLOPT_HEADER, 1);
6846 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
6847 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
6848 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
6849 curl_setopt($fp, CURLOPT_REFERER, $url);
6850 curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
6851 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
6852 if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
6853 {
6854 curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
6855 curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
6856 }
f2f7b699 6857
a6e043ff
AD
6858 /* Enable Digest authentication and SSL -fox */
6859 curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false);
6860 curl_setopt($fp, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
f2f7b699 6861
a6e043ff
AD
6862 $this->headers = curl_exec($fp);
6863 if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
6864 {
6865 curl_setopt($fp, CURLOPT_ENCODING, 'none');
6866 $this->headers = curl_exec($fp);
6867 }
6868 if (curl_errno($fp))
6869 {
6870 $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
6871 $this->success = false;
6872 }
6873 else
6874 {
6875 $info = curl_getinfo($fp);
6876 curl_close($fp);
6877 $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
6878 $this->headers = array_pop($this->headers);
6879 $parser = new SimplePie_HTTP_Parser($this->headers);
6880 if ($parser->parse())
6881 {
6882 $this->headers = $parser->headers;
6883 $this->body = $parser->body;
6884 $this->status_code = $parser->status_code;
6885 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
6886 {
6887 $this->redirects++;
6888 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6889 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6890 }
6891 }
6892 }
6893 }
6894 else
6895 {
6896 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
6897 $url_parts = parse_url($url);
6898 $socket_host = $url_parts['host'];
6899 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
6900 {
6901 $socket_host = "ssl://$url_parts[host]";
6902 $url_parts['port'] = 443;
6903 }
6904 if (!isset($url_parts['port']))
6905 {
6906 $url_parts['port'] = 80;
6907 }
6908 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
6909 if (!$fp)
6910 {
6911 $this->error = 'fsockopen error: ' . $errstr;
6912 $this->success = false;
6913 }
6914 else
6915 {
6916 stream_set_timeout($fp, $timeout);
6917 if (isset($url_parts['path']))
6918 {
6919 if (isset($url_parts['query']))
6920 {
6921 $get = "$url_parts[path]?$url_parts[query]";
6922 }
6923 else
6924 {
6925 $get = $url_parts['path'];
6926 }
6927 }
6928 else
6929 {
6930 $get = '/';
6931 }
6932 $out = "GET $get HTTP/1.1\r\n";
6933 $out .= "Host: $url_parts[host]\r\n";
6934 $out .= "User-Agent: $useragent\r\n";
6935 if (extension_loaded('zlib'))
6936 {
6937 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
6938 }
f2f7b699 6939
a6e043ff
AD
6940 if (isset($url_parts['user']) && isset($url_parts['pass']))
6941 {
6942 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
6943 }
6944 foreach ($headers as $key => $value)
6945 {
6946 $out .= "$key: $value\r\n";
6947 }
6948 $out .= "Connection: Close\r\n\r\n";
6949 fwrite($fp, $out);
f2f7b699 6950
a6e043ff
AD
6951 $info = stream_get_meta_data($fp);
6952
6953 $this->headers = '';
6954 while (!$info['eof'] && !$info['timed_out'])
6955 {
6956 $this->headers .= fread($fp, 1160);
6957 $info = stream_get_meta_data($fp);
6958 }
6959 if (!$info['timed_out'])
6960 {
6961 $parser = new SimplePie_HTTP_Parser($this->headers);
6962 if ($parser->parse())
6963 {
6964 $this->headers = $parser->headers;
6965 $this->body = $parser->body;
6966 $this->status_code = $parser->status_code;
6967 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
6968 {
6969 $this->redirects++;
6970 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6971 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6972 }
6973 if (isset($this->headers['content-encoding']))
6974 {
6975 // Hey, we act dumb elsewhere, so let's do that here too
6976 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
6977 {
6978 case 'gzip':
6979 case 'x-gzip':
6980 $decoder = new SimplePie_gzdecode($this->body);
6981 if (!$decoder->parse())
6982 {
6983 $this->error = 'Unable to decode HTTP "gzip" stream';
6984 $this->success = false;
6985 }
6986 else
6987 {
6988 $this->body = $decoder->data;
6989 }
6990 break;
6991
6992 case 'deflate':
6993 if (($decompressed = gzinflate($this->body)) !== false)
6994 {
6995 $this->body = $decompressed;
6996 }
6997 else if (($decompressed = gzuncompress($this->body)) !== false)
6998 {
6999 $this->body = $decompressed;
7000 }
7001 else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
7002 {
7003 $this->body = $decompressed;
7004 }
7005 else
7006 {
7007 $this->error = 'Unable to decode HTTP "deflate" stream';
7008 $this->success = false;
7009 }
7010 break;
7011
7012 default:
7013 $this->error = 'Unknown content coding';
7014 $this->success = false;
7015 }
7016 }
7017 }
7018 }
7019 else
7020 {
7021 $this->error = 'fsocket timed out';
7022 $this->success = false;
7023 }
7024 fclose($fp);
7025 }
7026 }
f2f7b699 7027 }
6d7d21a0 7028 else
f2f7b699 7029 {
a6e043ff
AD
7030 $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
7031 if (!$this->body = file_get_contents($url))
7032 {
7033 $this->error = 'file_get_contents could not read the file';
7034 $this->success = false;
7035 }
f2f7b699 7036 }
6d7d21a0 7037 }
a6e043ff 7038}
f2f7b699 7039
a6e043ff
AD
7040/**
7041 * Decode 'gzip' encoded HTTP data
7042 *
7043 * @package SimplePie
7044 * @subpackage HTTP
7045 * @link http://www.gzip.org/format.txt
7046 */
7047class SimplePie_gzdecode
7048{
7049 /**
7050 * Compressed data
7051 *
7052 * @access private
7053 * @var string
7054 * @see gzdecode::$data
7055 */
7056 var $compressed_data;
f2f7b699 7057
a6e043ff
AD
7058 /**
7059 * Size of compressed data
7060 *
7061 * @access private
7062 * @var int
7063 */
7064 var $compressed_size;
f2f7b699 7065
a6e043ff
AD
7066 /**
7067 * Minimum size of a valid gzip string
7068 *
7069 * @access private
7070 * @var int
7071 */
7072 var $min_compressed_size = 18;
f2f7b699 7073
a6e043ff
AD
7074 /**
7075 * Current position of pointer
7076 *
7077 * @access private
7078 * @var int
7079 */
7080 var $position = 0;
f2f7b699 7081
a6e043ff
AD
7082 /**
7083 * Flags (FLG)
7084 *
7085 * @access private
7086 * @var int
7087 */
7088 var $flags;
7089
7090 /**
7091 * Uncompressed data
7092 *
7093 * @access public
7094 * @see gzdecode::$compressed_data
7095 * @var string
7096 */
7097 var $data;
7098
7099 /**
7100 * Modified time
7101 *
7102 * @access public
7103 * @var int
7104 */
7105 var $MTIME;
7106
7107 /**
7108 * Extra Flags
7109 *
7110 * @access public
7111 * @var int
7112 */
7113 var $XFL;
7114
7115 /**
7116 * Operating System
7117 *
7118 * @access public
7119 * @var int
7120 */
7121 var $OS;
7122
7123 /**
7124 * Subfield ID 1
7125 *
7126 * @access public
7127 * @see gzdecode::$extra_field
7128 * @see gzdecode::$SI2
7129 * @var string
7130 */
7131 var $SI1;
7132
7133 /**
7134 * Subfield ID 2
7135 *
7136 * @access public
7137 * @see gzdecode::$extra_field
7138 * @see gzdecode::$SI1
7139 * @var string
7140 */
7141 var $SI2;
7142
7143 /**
7144 * Extra field content
7145 *
7146 * @access public
7147 * @see gzdecode::$SI1
7148 * @see gzdecode::$SI2
7149 * @var string
7150 */
7151 var $extra_field;
7152
7153 /**
7154 * Original filename
7155 *
7156 * @access public
7157 * @var string
7158 */
7159 var $filename;
7160
7161 /**
7162 * Human readable comment
7163 *
7164 * @access public
7165 * @var string
7166 */
7167 var $comment;
f2f7b699 7168
a6e043ff
AD
7169 /**
7170 * Don't allow anything to be set
7171 *
7172 * @param string $name
7173 * @param mixed $value
7174 */
7175 public function __set($name, $value)
6d7d21a0 7176 {
a6e043ff 7177 trigger_error("Cannot write property $name", E_USER_ERROR);
6d7d21a0
AD
7178 }
7179
a6e043ff
AD
7180 /**
7181 * Set the compressed string and related properties
7182 *
7183 * @param string $data
7184 */
7185 public function __construct($data)
6d7d21a0 7186 {
a6e043ff
AD
7187 $this->compressed_data = $data;
7188 $this->compressed_size = strlen($data);
6d7d21a0
AD
7189 }
7190
a6e043ff
AD
7191 /**
7192 * Decode the GZIP stream
7193 *
7194 * @return bool Successfulness
7195 */
7196 public function parse()
6d7d21a0 7197 {
a6e043ff 7198 if ($this->compressed_size >= $this->min_compressed_size)
6d7d21a0 7199 {
a6e043ff
AD
7200 // Check ID1, ID2, and CM
7201 if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
f2f7b699 7202 {
a6e043ff 7203 return false;
f2f7b699 7204 }
a6e043ff
AD
7205
7206 // Get the FLG (FLaGs)
7207 $this->flags = ord($this->compressed_data[3]);
7208
7209 // FLG bits above (1 << 4) are reserved
7210 if ($this->flags > 0x1F)
f2f7b699 7211 {
a6e043ff 7212 return false;
f2f7b699 7213 }
f2f7b699 7214
a6e043ff
AD
7215 // Advance the pointer after the above
7216 $this->position += 4;
f2f7b699 7217
a6e043ff
AD
7218 // MTIME
7219 $mtime = substr($this->compressed_data, $this->position, 4);
7220 // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
7221 if (current(unpack('S', "\x00\x01")) === 1)
6d7d21a0 7222 {
a6e043ff 7223 $mtime = strrev($mtime);
6d7d21a0 7224 }
a6e043ff
AD
7225 $this->MTIME = current(unpack('l', $mtime));
7226 $this->position += 4;
f2f7b699 7227
a6e043ff
AD
7228 // Get the XFL (eXtra FLags)
7229 $this->XFL = ord($this->compressed_data[$this->position++]);
7230
7231 // Get the OS (Operating System)
7232 $this->OS = ord($this->compressed_data[$this->position++]);
7233
7234 // Parse the FEXTRA
7235 if ($this->flags & 4)
7236 {
7237 // Read subfield IDs
7238 $this->SI1 = $this->compressed_data[$this->position++];
7239 $this->SI2 = $this->compressed_data[$this->position++];
7240
7241 // SI2 set to zero is reserved for future use
7242 if ($this->SI2 === "\x00")
7243 {
7244 return false;
7245 }
7246
7247 // Get the length of the extra field
7248 $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7249 $this->position += 2;
7250
7251 // Check the length of the string is still valid
7252 $this->min_compressed_size += $len + 4;
7253 if ($this->compressed_size >= $this->min_compressed_size)
7254 {
7255 // Set the extra field to the given data
7256 $this->extra_field = substr($this->compressed_data, $this->position, $len);
7257 $this->position += $len;
7258 }
7259 else
7260 {
7261 return false;
7262 }
7263 }
7264
7265 // Parse the FNAME
7266 if ($this->flags & 8)
7267 {
7268 // Get the length of the filename
7269 $len = strcspn($this->compressed_data, "\x00", $this->position);
7270
7271 // Check the length of the string is still valid
7272 $this->min_compressed_size += $len + 1;
7273 if ($this->compressed_size >= $this->min_compressed_size)
7274 {
7275 // Set the original filename to the given string
7276 $this->filename = substr($this->compressed_data, $this->position, $len);
7277 $this->position += $len + 1;
7278 }
7279 else
7280 {
7281 return false;
7282 }
7283 }
7284
7285 // Parse the FCOMMENT
7286 if ($this->flags & 16)
7287 {
7288 // Get the length of the comment
7289 $len = strcspn($this->compressed_data, "\x00", $this->position);
7290
7291 // Check the length of the string is still valid
7292 $this->min_compressed_size += $len + 1;
7293 if ($this->compressed_size >= $this->min_compressed_size)
7294 {
7295 // Set the original comment to the given string
7296 $this->comment = substr($this->compressed_data, $this->position, $len);
7297 $this->position += $len + 1;
7298 }
7299 else
7300 {
7301 return false;
7302 }
7303 }
7304
7305 // Parse the FHCRC
7306 if ($this->flags & 2)
7307 {
7308 // Check the length of the string is still valid
7309 $this->min_compressed_size += $len + 2;
7310 if ($this->compressed_size >= $this->min_compressed_size)
7311 {
7312 // Read the CRC
7313 $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7314
7315 // Check the CRC matches
7316 if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
7317 {
7318 $this->position += 2;
7319 }
7320 else
7321 {
7322 return false;
7323 }
7324 }
7325 else
7326 {
7327 return false;
7328 }
7329 }
7330
7331 // Decompress the actual data
7332 if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
7333 {
7334 return false;
7335 }
7336 else
7337 {
7338 $this->position = $this->compressed_size - 8;
7339 }
7340
7341 // Check CRC of data
7342 $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7343 $this->position += 4;
7344 /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
7345 {
7346 return false;
7347 }*/
7348
7349 // Check ISIZE of data
7350 $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7351 $this->position += 4;
7352 if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
7353 {
7354 return false;
7355 }
7356
7357 // Wow, against all odds, we've actually got a valid gzip string
7358 return true;
6d7d21a0
AD
7359 }
7360 else
7361 {
a6e043ff 7362 return false;
f2f7b699 7363 }
6d7d21a0 7364 }
a6e043ff 7365}
f2f7b699 7366
a6e043ff
AD
7367/**
7368 * HTTP Response Parser
7369 *
7370 * @package SimplePie
7371 * @subpackage HTTP
7372 */
7373class SimplePie_HTTP_Parser
7374{
7375 /**
7376 * HTTP Version
7377 *
7378 * @var float
7379 */
7380 public $http_version = 0.0;
7381
7382 /**
7383 * Status code
7384 *
7385 * @var int
7386 */
7387 public $status_code = 0;
7388
7389 /**
7390 * Reason phrase
7391 *
7392 * @var string
7393 */
7394 public $reason = '';
7395
7396 /**
7397 * Key/value pairs of the headers
7398 *
7399 * @var array
7400 */
7401 public $headers = array();
7402
7403 /**
7404 * Body of the response
7405 *
7406 * @var string
7407 */
7408 public $body = '';
7409
7410 /**
7411 * Current state of the state machine
7412 *
7413 * @var string
7414 */
7415 protected $state = 'http_version';
7416
7417 /**
7418 * Input data
7419 *
7420 * @var string
7421 */
7422 protected $data = '';
7423
7424 /**
7425 * Input data length (to avoid calling strlen() everytime this is needed)
7426 *
7427 * @var int
7428 */
7429 protected $data_length = 0;
f2f7b699 7430
a6e043ff
AD
7431 /**
7432 * Current position of the pointer
7433 *
7434 * @var int
7435 */
7436 protected $position = 0;
7437
7438 /**
7439 * Name of the hedaer currently being parsed
7440 *
7441 * @var string
7442 */
7443 protected $name = '';
7444
7445 /**
7446 * Value of the hedaer currently being parsed
7447 *
7448 * @var string
7449 */
7450 protected $value = '';
7451
7452 /**
7453 * Create an instance of the class with the input data
7454 *
7455 * @param string $data Input data
7456 */
7457 public function __construct($data)
6d7d21a0 7458 {
a6e043ff
AD
7459 $this->data = $data;
7460 $this->data_length = strlen($this->data);
6d7d21a0 7461 }
f2f7b699 7462
a6e043ff
AD
7463 /**
7464 * Parse the input data
7465 *
7466 * @return bool true on success, false on failure
7467 */
7468 public function parse()
6d7d21a0 7469 {
a6e043ff 7470 while ($this->state && $this->state !== 'emit' && $this->has_data())
6d7d21a0 7471 {
a6e043ff
AD
7472 $state = $this->state;
7473 $this->$state();
6d7d21a0 7474 }
a6e043ff
AD
7475 $this->data = '';
7476 if ($this->state === 'emit' || $this->state === 'body')
6d7d21a0 7477 {
a6e043ff 7478 return true;
6d7d21a0
AD
7479 }
7480 else
7481 {
a6e043ff
AD
7482 $this->http_version = '';
7483 $this->status_code = '';
7484 $this->reason = '';
7485 $this->headers = array();
7486 $this->body = '';
7487 return false;
6d7d21a0
AD
7488 }
7489 }
f2f7b699 7490
a6e043ff
AD
7491 /**
7492 * Check whether there is data beyond the pointer
7493 *
7494 * @return bool true if there is further data, false if not
7495 */
7496 protected function has_data()
7497 {
7498 return (bool) ($this->position < $this->data_length);
6d7d21a0 7499 }
f2f7b699 7500
a6e043ff
AD
7501 /**
7502 * See if the next character is LWS
7503 *
7504 * @return bool true if the next character is LWS, false if not
7505 */
7506 protected function is_linear_whitespace()
6d7d21a0 7507 {
a6e043ff
AD
7508 return (bool) ($this->data[$this->position] === "\x09"
7509 || $this->data[$this->position] === "\x20"
7510 || ($this->data[$this->position] === "\x0A"
7511 && isset($this->data[$this->position + 1])
7512 && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
6d7d21a0 7513 }
f2f7b699 7514
a6e043ff
AD
7515 /**
7516 * Parse the HTTP version
7517 */
7518 protected function http_version()
6d7d21a0 7519 {
a6e043ff 7520 if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
6d7d21a0 7521 {
a6e043ff
AD
7522 $len = strspn($this->data, '0123456789.', 5);
7523 $this->http_version = substr($this->data, 5, $len);
7524 $this->position += 5 + $len;
7525 if (substr_count($this->http_version, '.') <= 1)
7526 {
7527 $this->http_version = (float) $this->http_version;
7528 $this->position += strspn($this->data, "\x09\x20", $this->position);
7529 $this->state = 'status';
7530 }
7531 else
7532 {
7533 $this->state = false;
7534 }
6d7d21a0
AD
7535 }
7536 else
7537 {
a6e043ff 7538 $this->state = false;
6d7d21a0
AD
7539 }
7540 }
f2f7b699 7541
a6e043ff
AD
7542 /**
7543 * Parse the status code
7544 */
7545 protected function status()
6d7d21a0 7546 {
a6e043ff 7547 if ($len = strspn($this->data, '0123456789', $this->position))
f2f7b699 7548 {
a6e043ff
AD
7549 $this->status_code = (int) substr($this->data, $this->position, $len);
7550 $this->position += $len;
7551 $this->state = 'reason';
f2f7b699
AD
7552 }
7553 else
7554 {
a6e043ff 7555 $this->state = false;
f2f7b699
AD
7556 }
7557 }
f2f7b699 7558
a6e043ff
AD
7559 /**
7560 * Parse the reason phrase
7561 */
7562 protected function reason()
f2f7b699 7563 {
a6e043ff
AD
7564 $len = strcspn($this->data, "\x0A", $this->position);
7565 $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
7566 $this->position += $len + 1;
7567 $this->state = 'new_line';
f2f7b699
AD
7568 }
7569
a6e043ff
AD
7570 /**
7571 * Deal with a new line, shifting data around as needed
7572 */
7573 protected function new_line()
f2f7b699 7574 {
a6e043ff
AD
7575 $this->value = trim($this->value, "\x0D\x20");
7576 if ($this->name !== '' && $this->value !== '')
f2f7b699 7577 {
a6e043ff
AD
7578 $this->name = strtolower($this->name);
7579 // We should only use the last Content-Type header. c.f. issue #1
7580 if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
7581 {
7582 $this->headers[$this->name] .= ', ' . $this->value;
7583 }
7584 else
7585 {
7586 $this->headers[$this->name] = $this->value;
7587 }
f2f7b699 7588 }
a6e043ff
AD
7589 $this->name = '';
7590 $this->value = '';
7591 if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
f2f7b699 7592 {
a6e043ff
AD
7593 $this->position += 2;
7594 $this->state = 'body';
f2f7b699 7595 }
a6e043ff 7596 elseif ($this->data[$this->position] === "\x0A")
f2f7b699 7597 {
a6e043ff
AD
7598 $this->position++;
7599 $this->state = 'body';
f2f7b699
AD
7600 }
7601 else
7602 {
a6e043ff 7603 $this->state = 'name';
f2f7b699
AD
7604 }
7605 }
7606
a6e043ff
AD
7607 /**
7608 * Parse a header name
7609 */
7610 protected function name()
f2f7b699 7611 {
a6e043ff
AD
7612 $len = strcspn($this->data, "\x0A:", $this->position);
7613 if (isset($this->data[$this->position + $len]))
f2f7b699 7614 {
a6e043ff
AD
7615 if ($this->data[$this->position + $len] === "\x0A")
7616 {
7617 $this->position += $len;
7618 $this->state = 'new_line';
7619 }
7620 else
7621 {
7622 $this->name = substr($this->data, $this->position, $len);
7623 $this->position += $len + 1;
7624 $this->state = 'value';
7625 }
f2f7b699
AD
7626 }
7627 else
7628 {
a6e043ff 7629 $this->state = false;
f2f7b699
AD
7630 }
7631 }
7632
a6e043ff
AD
7633 /**
7634 * Parse LWS, replacing consecutive LWS characters with a single space
7635 */
7636 protected function linear_whitespace()
f2f7b699 7637 {
a6e043ff 7638 do
f2f7b699 7639 {
a6e043ff
AD
7640 if (substr($this->data, $this->position, 2) === "\x0D\x0A")
7641 {
7642 $this->position += 2;
7643 }
7644 elseif ($this->data[$this->position] === "\x0A")
7645 {
7646 $this->position++;
7647 }
7648 $this->position += strspn($this->data, "\x09\x20", $this->position);
7649 } while ($this->has_data() && $this->is_linear_whitespace());
7650 $this->value .= "\x20";
f2f7b699 7651 }
f2f7b699 7652
a6e043ff
AD
7653 /**
7654 * See what state to move to while within non-quoted header values
7655 */
7656 protected function value()
f2f7b699 7657 {
a6e043ff 7658 if ($this->is_linear_whitespace())
f2f7b699 7659 {
a6e043ff 7660 $this->linear_whitespace();
f2f7b699
AD
7661 }
7662 else
7663 {
a6e043ff
AD
7664 switch ($this->data[$this->position])
7665 {
7666 case '"':
7667 // Workaround for ETags: we have to include the quotes as
7668 // part of the tag.
7669 if (strtolower($this->name) === 'etag')
7670 {
7671 $this->value .= '"';
7672 $this->position++;
7673 $this->state = 'value_char';
7674 break;
7675 }
7676 $this->position++;
7677 $this->state = 'quote';
7678 break;
7679
7680 case "\x0A":
7681 $this->position++;
7682 $this->state = 'new_line';
7683 break;
7684
7685 default:
7686 $this->state = 'value_char';
7687 break;
7688 }
f2f7b699
AD
7689 }
7690 }
7691
a6e043ff
AD
7692 /**
7693 * Parse a header value while outside quotes
7694 */
7695 protected function value_char()
f2f7b699 7696 {
a6e043ff
AD
7697 $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
7698 $this->value .= substr($this->data, $this->position, $len);
7699 $this->position += $len;
7700 $this->state = 'value';
f2f7b699
AD
7701 }
7702
a6e043ff
AD
7703 /**
7704 * See what state to move to while within quoted header values
7705 */
7706 protected function quote()
f2f7b699 7707 {
a6e043ff 7708 if ($this->is_linear_whitespace())
f2f7b699 7709 {
a6e043ff 7710 $this->linear_whitespace();
f2f7b699
AD
7711 }
7712 else
7713 {
a6e043ff
AD
7714 switch ($this->data[$this->position])
7715 {
7716 case '"':
7717 $this->position++;
7718 $this->state = 'value';
7719 break;
7720
7721 case "\x0A":
7722 $this->position++;
7723 $this->state = 'new_line';
7724 break;
7725
7726 case '\\':
7727 $this->position++;
7728 $this->state = 'quote_escaped';
7729 break;
7730
7731 default:
7732 $this->state = 'quote_char';
7733 break;
7734 }
f2f7b699
AD
7735 }
7736 }
f2f7b699 7737
a6e043ff
AD
7738 /**
7739 * Parse a header value while within quotes
7740 */
7741 protected function quote_char()
f2f7b699 7742 {
a6e043ff
AD
7743 $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
7744 $this->value .= substr($this->data, $this->position, $len);
7745 $this->position += $len;
7746 $this->state = 'value';
7747 }
7748
7749 /**
7750 * Parse an escaped character within quotes
7751 */
7752 protected function quote_escaped()
7753 {
7754 $this->value .= $this->data[$this->position];
7755 $this->position++;
7756 $this->state = 'quote';
7757 }
7758
7759 /**
7760 * Parse the body
7761 */
7762 protected function body()
7763 {
7764 $this->body = substr($this->data, $this->position);
7765 if (!empty($this->headers['transfer-encoding']))
6d7d21a0 7766 {
a6e043ff
AD
7767 unset($this->headers['transfer-encoding']);
7768 $this->state = 'chunked';
6d7d21a0
AD
7769 }
7770 else
7771 {
a6e043ff 7772 $this->state = 'emit';
6d7d21a0 7773 }
f2f7b699
AD
7774 }
7775
a6e043ff
AD
7776 /**
7777 * Parsed a "Transfer-Encoding: chunked" body
7778 */
7779 protected function chunked()
7780 {
7781 if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
f2f7b699 7782 {
a6e043ff
AD
7783 $this->state = 'emit';
7784 return;
f2f7b699 7785 }
a6e043ff
AD
7786
7787 $decoded = '';
7788 $encoded = $this->body;
7789
7790 while (true)
f2f7b699 7791 {
a6e043ff
AD
7792 $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
7793 if (!$is_chunked)
7794 {
7795 // Looks like it's not chunked after all
7796 $this->state = 'emit';
7797 return;
7798 }
7799
7800 $length = hexdec(trim($matches[1]));
7801 if ($length === 0)
7802 {
7803 // Ignore trailer headers
7804 $this->state = 'emit';
7805 $this->body = $decoded;
7806 return;
7807 }
7808
7809 $chunk_length = strlen($matches[0]);
7810 $decoded .= $part = substr($encoded, $chunk_length, $length);
7811 $encoded = substr($encoded, $chunk_length + $length + 2);
7812
7813 if (trim($encoded) === '0' || empty($encoded))
7814 {
7815 $this->state = 'emit';
7816 $this->body = $decoded;
7817 return;
7818 }
f2f7b699
AD
7819 }
7820 }
a6e043ff
AD
7821}
7822
7823/**
7824 * IRI parser/serialiser/normaliser
7825 *
7826 * @package SimplePie
7827 * @subpackage HTTP
7828 * @author Geoffrey Sneddon
7829 * @author Steve Minutillo
7830 * @author Ryan McCue
7831 * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
7832 * @license http://www.opensource.org/licenses/bsd-license.php
7833 */
7834class SimplePie_IRI
7835{
7836 /**
7837 * Scheme
7838 *
7839 * @var string
7840 */
7841 protected $scheme = null;
7842
7843 /**
7844 * User Information
7845 *
7846 * @var string
7847 */
7848 protected $iuserinfo = null;
7849
7850 /**
7851 * ihost
7852 *
7853 * @var string
7854 */
7855 protected $ihost = null;
7856
7857 /**
7858 * Port
7859 *
7860 * @var string
7861 */
7862 protected $port = null;
7863
7864 /**
7865 * ipath
7866 *
7867 * @var string
7868 */
7869 protected $ipath = '';
7870
7871 /**
7872 * iquery
7873 *
7874 * @var string
7875 */
7876 protected $iquery = null;
7877
7878 /**
7879 * ifragment
7880 *
7881 * @var string
7882 */
7883 protected $ifragment = null;
7884
7885 /**
7886 * Normalization database
7887 *
7888 * Each key is the scheme, each value is an array with each key as the IRI
7889 * part and value as the default value for that part.
7890 */
7891 protected $normalization = array(
7892 'acap' => array(
7893 'port' => 674
7894 ),
7895 'dict' => array(
7896 'port' => 2628
7897 ),
7898 'file' => array(
7899 'ihost' => 'localhost'
7900 ),
7901 'http' => array(
7902 'port' => 80,
7903 'ipath' => '/'
7904 ),
7905 'https' => array(
7906 'port' => 443,
7907 'ipath' => '/'
7908 ),
7909 );
7910
7911 /**
7912 * Return the entire IRI when you try and read the object as a string
7913 *
7914 * @return string
7915 */
7916 public function __toString()
7917 {
7918 return $this->get_iri();
7919 }
f2f7b699 7920
a6e043ff
AD
7921 /**
7922 * Overload __set() to provide access via properties
7923 *
7924 * @param string $name Property name
7925 * @param mixed $value Property value
7926 */
7927 public function __set($name, $value)
f2f7b699 7928 {
a6e043ff 7929 if (method_exists($this, 'set_' . $name))
f2f7b699 7930 {
a6e043ff 7931 call_user_func(array($this, 'set_' . $name), $value);
f2f7b699 7932 }
a6e043ff
AD
7933 elseif (
7934 $name === 'iauthority'
7935 || $name === 'iuserinfo'
7936 || $name === 'ihost'
7937 || $name === 'ipath'
7938 || $name === 'iquery'
7939 || $name === 'ifragment'
7940 )
f2f7b699 7941 {
a6e043ff 7942 call_user_func(array($this, 'set_' . substr($name, 1)), $value);
f2f7b699
AD
7943 }
7944 }
f2f7b699 7945
a6e043ff
AD
7946 /**
7947 * Overload __get() to provide access via properties
7948 *
7949 * @param string $name Property name
7950 * @return mixed
7951 */
7952 public function __get($name)
f2f7b699 7953 {
a6e043ff
AD
7954 // isset() returns false for null, we don't want to do that
7955 // Also why we use array_key_exists below instead of isset()
7956 $props = get_object_vars($this);
7957
7958 if (
7959 $name === 'iri' ||
7960 $name === 'uri' ||
7961 $name === 'iauthority' ||
7962 $name === 'authority'
7963 )
f2f7b699 7964 {
a6e043ff
AD
7965 $return = $this->{"get_$name"}();
7966 }
7967 elseif (array_key_exists($name, $props))
7968 {
7969 $return = $this->$name;
7970 }
7971 // host -> ihost
7972 elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
7973 {
7974 $name = $prop;
7975 $return = $this->$prop;
7976 }
7977 // ischeme -> scheme
7978 elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
7979 {
7980 $name = $prop;
7981 $return = $this->$prop;
f2f7b699
AD
7982 }
7983 else
7984 {
a6e043ff
AD
7985 trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
7986 $return = null;
f2f7b699 7987 }
f2f7b699 7988
a6e043ff 7989 if ($return === null && isset($this->normalization[$this->scheme][$name]))
f2f7b699 7990 {
a6e043ff 7991 return $this->normalization[$this->scheme][$name];
f2f7b699
AD
7992 }
7993 else
7994 {
a6e043ff 7995 return $return;
f2f7b699
AD
7996 }
7997 }
f2f7b699 7998
a6e043ff
AD
7999 /**
8000 * Overload __isset() to provide access via properties
8001 *
8002 * @param string $name Property name
8003 * @return bool
8004 */
8005 public function __isset($name)
f2f7b699 8006 {
a6e043ff 8007 if (method_exists($this, 'get_' . $name) || isset($this->$name))
f2f7b699 8008 {
a6e043ff 8009 return true;
f2f7b699
AD
8010 }
8011 else
8012 {
a6e043ff 8013 return false;
f2f7b699
AD
8014 }
8015 }
8016
a6e043ff
AD
8017 /**
8018 * Overload __unset() to provide access via properties
8019 *
8020 * @param string $name Property name
8021 */
8022 public function __unset($name)
f2f7b699 8023 {
a6e043ff
AD
8024 if (method_exists($this, 'set_' . $name))
8025 {
8026 call_user_func(array($this, 'set_' . $name), '');
8027 }
f2f7b699
AD
8028 }
8029
6d7d21a0 8030 /**
a6e043ff
AD
8031 * Create a new IRI object, from a specified string
8032 *
8033 * @param string $iri
6d7d21a0 8034 */
a6e043ff 8035 public function __construct($iri = null)
f2f7b699 8036 {
a6e043ff
AD
8037 $this->set_iri($iri);
8038 }
6d7d21a0 8039
a6e043ff
AD
8040 /**
8041 * Create a new IRI object by resolving a relative IRI
8042 *
8043 * Returns false if $base is not absolute, otherwise an IRI.
8044 *
8045 * @param IRI|string $base (Absolute) Base IRI
8046 * @param IRI|string $relative Relative IRI
8047 * @return IRI|false
8048 */
8049 public static function absolutize($base, $relative)
8050 {
8051 if (!($relative instanceof SimplePie_IRI))
f2f7b699 8052 {
a6e043ff
AD
8053 $relative = new SimplePie_IRI($relative);
8054 }
8055 if (!$relative->is_valid())
8056 {
8057 return false;
8058 }
8059 elseif ($relative->scheme !== null)
8060 {
8061 return clone $relative;
f2f7b699
AD
8062 }
8063 else
8064 {
a6e043ff 8065 if (!($base instanceof SimplePie_IRI))
6d7d21a0 8066 {
a6e043ff 8067 $base = new SimplePie_IRI($base);
6d7d21a0 8068 }
a6e043ff 8069 if ($base->scheme !== null && $base->is_valid())
f2f7b699 8070 {
a6e043ff 8071 if ($relative->get_iri() !== '')
f2f7b699 8072 {
a6e043ff
AD
8073 if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
8074 {
8075 $target = clone $relative;
8076 $target->scheme = $base->scheme;
8077 }
8078 else
8079 {
8080 $target = new SimplePie_IRI;
8081 $target->scheme = $base->scheme;
8082 $target->iuserinfo = $base->iuserinfo;
8083 $target->ihost = $base->ihost;
8084 $target->port = $base->port;
8085 if ($relative->ipath !== '')
8086 {
8087 if ($relative->ipath[0] === '/')
8088 {
8089 $target->ipath = $relative->ipath;
8090 }
8091 elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
8092 {
8093 $target->ipath = '/' . $relative->ipath;
8094 }
8095 elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
8096 {
8097 $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
8098 }
8099 else
8100 {
8101 $target->ipath = $relative->ipath;
8102 }
8103 $target->ipath = $target->remove_dot_segments($target->ipath);
8104 $target->iquery = $relative->iquery;
8105 }
8106 else
8107 {
8108 $target->ipath = $base->ipath;
8109 if ($relative->iquery !== null)
8110 {
8111 $target->iquery = $relative->iquery;
8112 }
8113 elseif ($base->iquery !== null)
8114 {
8115 $target->iquery = $base->iquery;
8116 }
8117 }
8118 $target->ifragment = $relative->ifragment;
8119 }
f2f7b699 8120 }
6d7d21a0 8121 else
f2f7b699 8122 {
a6e043ff
AD
8123 $target = clone $base;
8124 $target->ifragment = null;
f2f7b699 8125 }
a6e043ff
AD
8126 $target->scheme_normalization();
8127 return $target;
6d7d21a0
AD
8128 }
8129 else
8130 {
a6e043ff 8131 return false;
6d7d21a0
AD
8132 }
8133 }
a6e043ff 8134 }
f2f7b699 8135
a6e043ff
AD
8136 /**
8137 * Parse an IRI into scheme/authority/path/query/fragment segments
8138 *
8139 * @param string $iri
8140 * @return array
8141 */
8142 protected function parse_iri($iri)
8143 {
8144 $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
8145 if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
8146 {
8147 if ($match[1] === '')
6d7d21a0 8148 {
a6e043ff 8149 $match['scheme'] = null;
f2f7b699 8150 }
a6e043ff 8151 if (!isset($match[3]) || $match[3] === '')
f2f7b699 8152 {
a6e043ff 8153 $match['authority'] = null;
6d7d21a0 8154 }
a6e043ff 8155 if (!isset($match[5]))
6d7d21a0 8156 {
a6e043ff 8157 $match['path'] = '';
f2f7b699 8158 }
a6e043ff 8159 if (!isset($match[6]) || $match[6] === '')
f2f7b699 8160 {
a6e043ff 8161 $match['query'] = null;
6d7d21a0 8162 }
a6e043ff 8163 if (!isset($match[8]) || $match[8] === '')
6d7d21a0 8164 {
a6e043ff 8165 $match['fragment'] = null;
f2f7b699 8166 }
a6e043ff
AD
8167 return $match;
8168 }
8169 else
8170 {
8171 // This can occur when a paragraph is accidentally parsed as a URI
8172 return false;
f2f7b699 8173 }
a6e043ff 8174 }
6d7d21a0 8175
a6e043ff
AD
8176 /**
8177 * Remove dot segments from a path
8178 *
8179 * @param string $input
8180 * @return string
8181 */
8182 protected function remove_dot_segments($input)
8183 {
8184 $output = '';
8185 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
f2f7b699 8186 {
a6e043ff
AD
8187 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
8188 if (strpos($input, '../') === 0)
f2f7b699 8189 {
a6e043ff 8190 $input = substr($input, 3);
f2f7b699 8191 }
a6e043ff 8192 elseif (strpos($input, './') === 0)
f2f7b699 8193 {
a6e043ff 8194 $input = substr($input, 2);
f2f7b699 8195 }
a6e043ff
AD
8196 // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
8197 elseif (strpos($input, '/./') === 0)
6d7d21a0 8198 {
a6e043ff 8199 $input = substr($input, 2);
6d7d21a0 8200 }
a6e043ff 8201 elseif ($input === '/.')
6d7d21a0 8202 {
a6e043ff 8203 $input = '/';
6d7d21a0 8204 }
a6e043ff
AD
8205 // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
8206 elseif (strpos($input, '/../') === 0)
6d7d21a0 8207 {
a6e043ff
AD
8208 $input = substr($input, 3);
8209 $output = substr_replace($output, '', strrpos($output, '/'));
6d7d21a0 8210 }
a6e043ff 8211 elseif ($input === '/..')
6d7d21a0 8212 {
a6e043ff
AD
8213 $input = '/';
8214 $output = substr_replace($output, '', strrpos($output, '/'));
6d7d21a0 8215 }
a6e043ff
AD
8216 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
8217 elseif ($input === '.' || $input === '..')
6d7d21a0 8218 {
a6e043ff
AD
8219 $input = '';
8220 }
8221 // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
8222 elseif (($pos = strpos($input, '/', 1)) !== false)
8223 {
8224 $output .= substr($input, 0, $pos);
8225 $input = substr_replace($input, '', 0, $pos);
6d7d21a0
AD
8226 }
8227 else
8228 {
a6e043ff
AD
8229 $output .= $input;
8230 $input = '';
6d7d21a0
AD
8231 }
8232 }
a6e043ff 8233 return $output . $input;
6d7d21a0 8234 }
f2f7b699 8235
a6e043ff
AD
8236 /**
8237 * Replace invalid character with percent encoding
8238 *
8239 * @param string $string Input string
8240 * @param string $extra_chars Valid characters not in iunreserved or
8241 * iprivate (this is ASCII-only)
8242 * @param bool $iprivate Allow iprivate
8243 * @return string
8244 */
8245 protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
f2f7b699 8246 {
a6e043ff
AD
8247 // Normalize as many pct-encoded sections as possible
8248 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
f2f7b699 8249
a6e043ff
AD
8250 // Replace invalid percent characters
8251 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
f2f7b699 8252
a6e043ff
AD
8253 // Add unreserved and % to $extra_chars (the latter is safe because all
8254 // pct-encoded sections are now valid).
8255 $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
f2f7b699 8256
a6e043ff
AD
8257 // Now replace any bytes that aren't allowed with their pct-encoded versions
8258 $position = 0;
8259 $strlen = strlen($string);
8260 while (($position += strspn($string, $extra_chars, $position)) < $strlen)
f2f7b699 8261 {
a6e043ff 8262 $value = ord($string[$position]);
f2f7b699 8263
a6e043ff
AD
8264 // Start position
8265 $start = $position;
f2f7b699 8266
a6e043ff
AD
8267 // By default we are valid
8268 $valid = true;
f2f7b699 8269
a6e043ff
AD
8270 // No one byte sequences are valid due to the while.
8271 // Two byte sequence:
8272 if (($value & 0xE0) === 0xC0)
8273 {
8274 $character = ($value & 0x1F) << 6;
8275 $length = 2;
8276 $remaining = 1;
8277 }
8278 // Three byte sequence:
8279 elseif (($value & 0xF0) === 0xE0)
8280 {
8281 $character = ($value & 0x0F) << 12;
8282 $length = 3;
8283 $remaining = 2;
8284 }
8285 // Four byte sequence:
8286 elseif (($value & 0xF8) === 0xF0)
8287 {
8288 $character = ($value & 0x07) << 18;
8289 $length = 4;
8290 $remaining = 3;
8291 }
8292 // Invalid byte:
8293 else
8294 {
8295 $valid = false;
8296 $length = 1;
8297 $remaining = 0;
8298 }
f2f7b699 8299
a6e043ff
AD
8300 if ($remaining)
8301 {
8302 if ($position + $length <= $strlen)
8303 {
8304 for ($position++; $remaining; $position++)
8305 {
8306 $value = ord($string[$position]);
f2f7b699 8307
a6e043ff
AD
8308 // Check that the byte is valid, then add it to the character:
8309 if (($value & 0xC0) === 0x80)
8310 {
8311 $character |= ($value & 0x3F) << (--$remaining * 6);
8312 }
8313 // If it is invalid, count the sequence as invalid and reprocess the current byte:
8314 else
8315 {
8316 $valid = false;
8317 $position--;
8318 break;
8319 }
8320 }
8321 }
8322 else
8323 {
8324 $position = $strlen - 1;
8325 $valid = false;
8326 }
8327 }
f2f7b699 8328
a6e043ff
AD
8329 // Percent encode anything invalid or not in ucschar
8330 if (
8331 // Invalid sequences
8332 !$valid
8333 // Non-shortest form sequences are invalid
8334 || $length > 1 && $character <= 0x7F
8335 || $length > 2 && $character <= 0x7FF
8336 || $length > 3 && $character <= 0xFFFF
8337 // Outside of range of ucschar codepoints
8338 // Noncharacters
8339 || ($character & 0xFFFE) === 0xFFFE
8340 || $character >= 0xFDD0 && $character <= 0xFDEF
8341 || (
8342 // Everything else not in ucschar
8343 $character > 0xD7FF && $character < 0xF900
8344 || $character < 0xA0
8345 || $character > 0xEFFFD
8346 )
8347 && (
8348 // Everything not in iprivate, if it applies
8349 !$iprivate
8350 || $character < 0xE000
8351 || $character > 0x10FFFD
8352 )
8353 )
8354 {
8355 // If we were a character, pretend we weren't, but rather an error.
8356 if ($valid)
8357 $position--;
f2f7b699 8358
a6e043ff
AD
8359 for ($j = $start; $j <= $position; $j++)
8360 {
8361 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
8362 $j += 2;
8363 $position += 2;
8364 $strlen += 2;
8365 }
8366 }
8367 }
f2f7b699 8368
a6e043ff
AD
8369 return $string;
8370 }
f2f7b699 8371
a6e043ff
AD
8372 /**
8373 * Callback function for preg_replace_callback.
8374 *
8375 * Removes sequences of percent encoded bytes that represent UTF-8
8376 * encoded characters in iunreserved
8377 *
8378 * @param array $match PCRE match
8379 * @return string Replacement
8380 */
8381 protected function remove_iunreserved_percent_encoded($match)
8382 {
8383 // As we just have valid percent encoded sequences we can just explode
8384 // and ignore the first member of the returned array (an empty string).
8385 $bytes = explode('%', $match[0]);
6d7d21a0 8386
a6e043ff
AD
8387 // Initialize the new string (this is what will be returned) and that
8388 // there are no bytes remaining in the current sequence (unsurprising
8389 // at the first byte!).
8390 $string = '';
8391 $remaining = 0;
6d7d21a0 8392
a6e043ff
AD
8393 // Loop over each and every byte, and set $value to its value
8394 for ($i = 1, $len = count($bytes); $i < $len; $i++)
8395 {
8396 $value = hexdec($bytes[$i]);
6d7d21a0 8397
a6e043ff
AD
8398 // If we're the first byte of sequence:
8399 if (!$remaining)
8400 {
8401 // Start position
8402 $start = $i;
6d7d21a0 8403
a6e043ff
AD
8404 // By default we are valid
8405 $valid = true;
6d7d21a0 8406
a6e043ff
AD
8407 // One byte sequence:
8408 if ($value <= 0x7F)
8409 {
8410 $character = $value;
8411 $length = 1;
8412 }
8413 // Two byte sequence:
8414 elseif (($value & 0xE0) === 0xC0)
8415 {
8416 $character = ($value & 0x1F) << 6;
8417 $length = 2;
8418 $remaining = 1;
8419 }
8420 // Three byte sequence:
8421 elseif (($value & 0xF0) === 0xE0)
8422 {
8423 $character = ($value & 0x0F) << 12;
8424 $length = 3;
8425 $remaining = 2;
8426 }
8427 // Four byte sequence:
8428 elseif (($value & 0xF8) === 0xF0)
8429 {
8430 $character = ($value & 0x07) << 18;
8431 $length = 4;
8432 $remaining = 3;
8433 }
8434 // Invalid byte:
8435 else
8436 {
8437 $valid = false;
8438 $remaining = 0;
8439 }
8440 }
8441 // Continuation byte:
8442 else
8443 {
8444 // Check that the byte is valid, then add it to the character:
8445 if (($value & 0xC0) === 0x80)
8446 {
8447 $remaining--;
8448 $character |= ($value & 0x3F) << ($remaining * 6);
8449 }
8450 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
8451 else
8452 {
8453 $valid = false;
8454 $remaining = 0;
8455 $i--;
8456 }
8457 }
6d7d21a0 8458
a6e043ff
AD
8459 // If we've reached the end of the current byte sequence, append it to Unicode::$data
8460 if (!$remaining)
8461 {
8462 // Percent encode anything invalid or not in iunreserved
8463 if (
8464 // Invalid sequences
8465 !$valid
8466 // Non-shortest form sequences are invalid
8467 || $length > 1 && $character <= 0x7F
8468 || $length > 2 && $character <= 0x7FF
8469 || $length > 3 && $character <= 0xFFFF
8470 // Outside of range of iunreserved codepoints
8471 || $character < 0x2D
8472 || $character > 0xEFFFD
8473 // Noncharacters
8474 || ($character & 0xFFFE) === 0xFFFE
8475 || $character >= 0xFDD0 && $character <= 0xFDEF
8476 // Everything else not in iunreserved (this is all BMP)
8477 || $character === 0x2F
8478 || $character > 0x39 && $character < 0x41
8479 || $character > 0x5A && $character < 0x61
8480 || $character > 0x7A && $character < 0x7E
8481 || $character > 0x7E && $character < 0xA0
8482 || $character > 0xD7FF && $character < 0xF900
8483 )
8484 {
8485 for ($j = $start; $j <= $i; $j++)
8486 {
8487 $string .= '%' . strtoupper($bytes[$j]);
8488 }
8489 }
8490 else
8491 {
8492 for ($j = $start; $j <= $i; $j++)
8493 {
8494 $string .= chr(hexdec($bytes[$j]));
8495 }
8496 }
6d7d21a0 8497 }
f2f7b699 8498 }
6d7d21a0 8499
a6e043ff
AD
8500 // If we have any bytes left over they are invalid (i.e., we are
8501 // mid-way through a multi-byte sequence)
8502 if ($remaining)
f2f7b699 8503 {
a6e043ff 8504 for ($j = $start; $j < $len; $j++)
6d7d21a0 8505 {
a6e043ff 8506 $string .= '%' . strtoupper($bytes[$j]);
6d7d21a0 8507 }
f2f7b699 8508 }
a6e043ff
AD
8509
8510 return $string;
8511 }
8512
8513 protected function scheme_normalization()
8514 {
8515 if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
f2f7b699 8516 {
a6e043ff
AD
8517 $this->iuserinfo = null;
8518 }
8519 if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
8520 {
8521 $this->ihost = null;
8522 }
8523 if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
8524 {
8525 $this->port = null;
8526 }
8527 if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
8528 {
8529 $this->ipath = '';
8530 }
8531 if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
8532 {
8533 $this->iquery = null;
8534 }
8535 if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
8536 {
8537 $this->ifragment = null;
f2f7b699
AD
8538 }
8539 }
f2f7b699 8540
a6e043ff
AD
8541 /**
8542 * Check if the object represents a valid IRI. This needs to be done on each
8543 * call as some things change depending on another part of the IRI.
8544 *
8545 * @return bool
8546 */
8547 public function is_valid()
8548 {
8549 $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
8550 if ($this->ipath !== '' &&
8551 (
8552 $isauthority && (
8553 $this->ipath[0] !== '/' ||
8554 substr($this->ipath, 0, 2) === '//'
8555 ) ||
8556 (
8557 $this->scheme === null &&
8558 !$isauthority &&
8559 strpos($this->ipath, ':') !== false &&
8560 (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
8561 )
8562 )
8563 )
8564 {
8565 return false;
8566 }
f2f7b699 8567
a6e043ff 8568 return true;
f2f7b699
AD
8569 }
8570
a6e043ff
AD
8571 /**
8572 * Set the entire IRI. Returns true on success, false on failure (if there
8573 * are any invalid characters).
8574 *
8575 * @param string $iri
8576 * @return bool
8577 */
8578 public function set_iri($iri)
f2f7b699 8579 {
a6e043ff
AD
8580 static $cache;
8581 if (!$cache)
8582 {
8583 $cache = array();
8584 }
f2f7b699 8585
a6e043ff 8586 if ($iri === null)
f2f7b699 8587 {
a6e043ff
AD
8588 return true;
8589 }
8590 elseif (isset($cache[$iri]))
8591 {
8592 list($this->scheme,
8593 $this->iuserinfo,
8594 $this->ihost,
8595 $this->port,
8596 $this->ipath,
8597 $this->iquery,
8598 $this->ifragment,
8599 $return) = $cache[$iri];
8600 return $return;
6d7d21a0
AD
8601 }
8602 else
8603 {
a6e043ff
AD
8604 $parsed = $this->parse_iri((string) $iri);
8605 if (!$parsed)
8606 {
8607 return false;
8608 }
8609
8610 $return = $this->set_scheme($parsed['scheme'])
8611 && $this->set_authority($parsed['authority'])
8612 && $this->set_path($parsed['path'])
8613 && $this->set_query($parsed['query'])
8614 && $this->set_fragment($parsed['fragment']);
8615
8616 $cache[$iri] = array($this->scheme,
8617 $this->iuserinfo,
8618 $this->ihost,
8619 $this->port,
8620 $this->ipath,
8621 $this->iquery,
8622 $this->ifragment,
8623 $return);
8624 return $return;
f2f7b699 8625 }
f2f7b699
AD
8626 }
8627
a6e043ff
AD
8628 /**
8629 * Set the scheme. Returns true on success, false on failure (if there are
8630 * any invalid characters).
8631 *
8632 * @param string $scheme
8633 * @return bool
8634 */
8635 public function set_scheme($scheme)
f2f7b699 8636 {
a6e043ff 8637 if ($scheme === null)
f2f7b699 8638 {
a6e043ff
AD
8639 $this->scheme = null;
8640 }
8641 elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
8642 {
8643 $this->scheme = null;
8644 return false;
6d7d21a0
AD
8645 }
8646 else
8647 {
a6e043ff 8648 $this->scheme = strtolower($scheme);
f2f7b699 8649 }
a6e043ff 8650 return true;
f2f7b699
AD
8651 }
8652
a6e043ff
AD
8653 /**
8654 * Set the authority. Returns true on success, false on failure (if there are
8655 * any invalid characters).
8656 *
8657 * @param string $authority
8658 * @return bool
8659 */
8660 public function set_authority($authority)
f2f7b699 8661 {
a6e043ff
AD
8662 static $cache;
8663 if (!$cache)
8664 $cache = array();
8665
8666 if ($authority === null)
f2f7b699 8667 {
a6e043ff
AD
8668 $this->iuserinfo = null;
8669 $this->ihost = null;
8670 $this->port = null;
8671 return true;
8672 }
8673 elseif (isset($cache[$authority]))
8674 {
8675 list($this->iuserinfo,
8676 $this->ihost,
8677 $this->port,
8678 $return) = $cache[$authority];
8679
8680 return $return;
6d7d21a0
AD
8681 }
8682 else
8683 {
a6e043ff
AD
8684 $remaining = $authority;
8685 if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
8686 {
8687 $iuserinfo = substr($remaining, 0, $iuserinfo_end);
8688 $remaining = substr($remaining, $iuserinfo_end + 1);
8689 }
8690 else
8691 {
8692 $iuserinfo = null;
8693 }
8694 if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
8695 {
8696 if (($port = substr($remaining, $port_start + 1)) === false)
8697 {
8698 $port = null;
8699 }
8700 $remaining = substr($remaining, 0, $port_start);
8701 }
8702 else
8703 {
8704 $port = null;
8705 }
8706
8707 $return = $this->set_userinfo($iuserinfo) &&
8708 $this->set_host($remaining) &&
8709 $this->set_port($port);
8710
8711 $cache[$authority] = array($this->iuserinfo,
8712 $this->ihost,
8713 $this->port,
8714 $return);
8715
8716 return $return;
f2f7b699 8717 }
f2f7b699
AD
8718 }
8719
a6e043ff
AD
8720 /**
8721 * Set the iuserinfo.
8722 *
8723 * @param string $iuserinfo
8724 * @return bool
8725 */
8726 public function set_userinfo($iuserinfo)
f2f7b699 8727 {
a6e043ff 8728 if ($iuserinfo === null)
f2f7b699 8729 {
a6e043ff 8730 $this->iuserinfo = null;
6d7d21a0
AD
8731 }
8732 else
8733 {
a6e043ff
AD
8734 $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
8735 $this->scheme_normalization();
f2f7b699 8736 }
a6e043ff
AD
8737
8738 return true;
f2f7b699 8739 }
f2f7b699 8740
a6e043ff
AD
8741 /**
8742 * Set the ihost. Returns true on success, false on failure (if there are
8743 * any invalid characters).
8744 *
8745 * @param string $ihost
8746 * @return bool
8747 */
8748 public function set_host($ihost)
f2f7b699 8749 {
a6e043ff 8750 if ($ihost === null)
f2f7b699 8751 {
a6e043ff
AD
8752 $this->ihost = null;
8753 return true;
f2f7b699 8754 }
a6e043ff 8755 elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
f2f7b699 8756 {
a6e043ff
AD
8757 if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
8758 {
8759 $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
8760 }
8761 else
8762 {
8763 $this->ihost = null;
8764 return false;
8765 }
f2f7b699 8766 }
a6e043ff
AD
8767 else
8768 {
8769 $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
f2f7b699 8770
a6e043ff
AD
8771 // Lowercase, but ignore pct-encoded sections (as they should
8772 // remain uppercase). This must be done after the previous step
8773 // as that can add unescaped characters.
8774 $position = 0;
8775 $strlen = strlen($ihost);
8776 while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
8777 {
8778 if ($ihost[$position] === '%')
8779 {
8780 $position += 3;
8781 }
8782 else
8783 {
8784 $ihost[$position] = strtolower($ihost[$position]);
8785 $position++;
8786 }
8787 }
f2f7b699 8788
a6e043ff
AD
8789 $this->ihost = $ihost;
8790 }
f2f7b699 8791
a6e043ff
AD
8792 $this->scheme_normalization();
8793
8794 return true;
6d7d21a0
AD
8795 }
8796
a6e043ff
AD
8797 /**
8798 * Set the port. Returns true on success, false on failure (if there are
8799 * any invalid characters).
8800 *
8801 * @param string $port
8802 * @return bool
8803 */
8804 public function set_port($port)
6d7d21a0 8805 {
a6e043ff 8806 if ($port === null)
f2f7b699 8807 {
a6e043ff
AD
8808 $this->port = null;
8809 return true;
8810 }
8811 elseif (strspn($port, '0123456789') === strlen($port))
8812 {
8813 $this->port = (int) $port;
8814 $this->scheme_normalization();
8815 return true;
f2f7b699
AD
8816 }
8817 else
8818 {
a6e043ff
AD
8819 $this->port = null;
8820 return false;
f2f7b699 8821 }
f2f7b699
AD
8822 }
8823
a6e043ff
AD
8824 /**
8825 * Set the ipath.
8826 *
8827 * @param string $ipath
8828 * @return bool
8829 */
8830 public function set_path($ipath)
f2f7b699 8831 {
a6e043ff
AD
8832 static $cache;
8833 if (!$cache)
6d7d21a0 8834 {
a6e043ff 8835 $cache = array();
f2f7b699 8836 }
f2f7b699 8837
a6e043ff
AD
8838 $ipath = (string) $ipath;
8839
8840 if (isset($cache[$ipath]))
f2f7b699 8841 {
a6e043ff 8842 $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
6d7d21a0
AD
8843 }
8844 else
8845 {
a6e043ff
AD
8846 $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
8847 $removed = $this->remove_dot_segments($valid);
6d7d21a0 8848
a6e043ff
AD
8849 $cache[$ipath] = array($valid, $removed);
8850 $this->ipath = ($this->scheme !== null) ? $removed : $valid;
8851 }
6d7d21a0 8852
a6e043ff
AD
8853 $this->scheme_normalization();
8854 return true;
6d7d21a0
AD
8855 }
8856
a6e043ff
AD
8857 /**
8858 * Set the iquery.
8859 *
8860 * @param string $iquery
8861 * @return bool
8862 */
8863 public function set_query($iquery)
6d7d21a0 8864 {
a6e043ff 8865 if ($iquery === null)
f2f7b699 8866 {
a6e043ff 8867 $this->iquery = null;
f2f7b699
AD
8868 }
8869 else
8870 {
a6e043ff
AD
8871 $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
8872 $this->scheme_normalization();
f2f7b699 8873 }
a6e043ff 8874 return true;
f2f7b699
AD
8875 }
8876
a6e043ff
AD
8877 /**
8878 * Set the ifragment.
8879 *
8880 * @param string $ifragment
8881 * @return bool
8882 */
8883 public function set_fragment($ifragment)
f2f7b699 8884 {
a6e043ff 8885 if ($ifragment === null)
f2f7b699 8886 {
a6e043ff 8887 $this->ifragment = null;
f2f7b699 8888 }
6d7d21a0 8889 else
f2f7b699 8890 {
a6e043ff
AD
8891 $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
8892 $this->scheme_normalization();
f2f7b699 8893 }
a6e043ff 8894 return true;
6d7d21a0 8895 }
f2f7b699 8896
a6e043ff
AD
8897 /**
8898 * Convert an IRI to a URI (or parts thereof)
8899 *
8900 * @return string
8901 */
8902 public function to_uri($string)
6d7d21a0 8903 {
a6e043ff
AD
8904 static $non_ascii;
8905 if (!$non_ascii)
8906 {
8907 $non_ascii = implode('', range("\x80", "\xFF"));
8908 }
f2f7b699 8909
a6e043ff
AD
8910 $position = 0;
8911 $strlen = strlen($string);
8912 while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
8913 {
8914 $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
8915 $position += 3;
8916 $strlen += 2;
8917 }
8918
8919 return $string;
6d7d21a0 8920 }
f2f7b699 8921
a6e043ff
AD
8922 /**
8923 * Get the complete IRI
8924 *
8925 * @return string
8926 */
8927 public function get_iri()
6d7d21a0 8928 {
a6e043ff
AD
8929 if (!$this->is_valid())
8930 {
8931 return false;
8932 }
8933
8934 $iri = '';
6d7d21a0 8935 if ($this->scheme !== null)
f2f7b699 8936 {
a6e043ff 8937 $iri .= $this->scheme . ':';
f2f7b699 8938 }
a6e043ff 8939 if (($iauthority = $this->get_iauthority()) !== null)
f2f7b699 8940 {
a6e043ff
AD
8941 $iri .= '//' . $iauthority;
8942 }
8943 if ($this->ipath !== '')
8944 {
8945 $iri .= $this->ipath;
8946 }
8947 elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
8948 {
8949 $iri .= $this->normalization[$this->scheme]['ipath'];
8950 }
8951 if ($this->iquery !== null)
8952 {
8953 $iri .= '?' . $this->iquery;
8954 }
8955 if ($this->ifragment !== null)
8956 {
8957 $iri .= '#' . $this->ifragment;
f2f7b699 8958 }
a6e043ff
AD
8959
8960 return $iri;
f2f7b699
AD
8961 }
8962
a6e043ff
AD
8963 /**
8964 * Get the complete URI
8965 *
8966 * @return string
8967 */
8968 public function get_uri()
f2f7b699 8969 {
a6e043ff
AD
8970 return $this->to_uri($this->get_iri());
8971 }
8972
8973 /**
8974 * Get the complete iauthority
8975 *
8976 * @return string
8977 */
8978 protected function get_iauthority()
8979 {
8980 if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
f2f7b699 8981 {
a6e043ff
AD
8982 $iauthority = '';
8983 if ($this->iuserinfo !== null)
8984 {
8985 $iauthority .= $this->iuserinfo . '@';
8986 }
8987 if ($this->ihost !== null)
8988 {
8989 $iauthority .= $this->ihost;
8990 }
8991 if ($this->port !== null)
8992 {
8993 $iauthority .= ':' . $this->port;
8994 }
8995 return $iauthority;
f2f7b699
AD
8996 }
8997 else
8998 {
6d7d21a0 8999 return null;
f2f7b699
AD
9000 }
9001 }
a6e043ff
AD
9002
9003 /**
9004 * Get the complete authority
9005 *
9006 * @return string
9007 */
9008 protected function get_authority()
9009 {
9010 $iauthority = $this->get_iauthority();
9011 if (is_string($iauthority))
9012 return $this->to_uri($iauthority);
9013 else
9014 return $iauthority;
9015 }
6d7d21a0 9016}
f2f7b699 9017
a6e043ff
AD
9018/**
9019 * Manages all item-related data
9020 *
9021 * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
9022 *
9023 * This class can be overloaded with {@see SimplePie::set_item_class()}
9024 *
9025 * @package SimplePie
9026 * @subpackage API
9027 */
9028class SimplePie_Item
6d7d21a0 9029{
a6e043ff
AD
9030 /**
9031 * Parent feed
9032 *
9033 * @access private
9034 * @var SimplePie
9035 */
9036 var $feed;
9037
9038 /**
9039 * Raw data
9040 *
9041 * @access private
9042 * @var array
9043 */
9044 var $data = array();
9045
9046 /**
9047 * Registry object
9048 *
9049 * @see set_registry
9050 * @var SimplePie_Registry
9051 */
9052 protected $registry;
6d7d21a0 9053
a6e043ff
AD
9054 /**
9055 * Create a new item object
9056 *
9057 * This is usually used by {@see SimplePie::get_items} and
9058 * {@see SimplePie::get_item}. Avoid creating this manually.
9059 *
9060 * @param SimplePie $feed Parent feed
9061 * @param array $data Raw data
9062 */
9063 public function __construct($feed, $data)
f2f7b699 9064 {
a6e043ff
AD
9065 $this->feed = $feed;
9066 $this->data = $data;
f2f7b699
AD
9067 }
9068
a6e043ff
AD
9069 /**
9070 * Set the registry handler
9071 *
9072 * This is usually used by {@see SimplePie_Registry::create}
9073 *
9074 * @since 1.3
9075 * @param SimplePie_Registry $registry
9076 */
9077 public function set_registry(SimplePie_Registry $registry)
f2f7b699 9078 {
a6e043ff 9079 $this->registry = $registry;
f2f7b699
AD
9080 }
9081
a6e043ff
AD
9082 /**
9083 * Get a string representation of the item
9084 *
9085 * @return string
9086 */
9087 public function __toString()
f2f7b699 9088 {
a6e043ff
AD
9089 return md5(serialize($this->data));
9090 }
9091
9092 /**
9093 * Remove items that link back to this before destroying this object
9094 */
9095 public function __destruct()
9096 {
9097 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
f2f7b699 9098 {
a6e043ff 9099 unset($this->feed);
f2f7b699
AD
9100 }
9101 }
9102
a6e043ff
AD
9103 /**
9104 * Get data for an item-level element
9105 *
9106 * This method allows you to get access to ANY element/attribute that is a
9107 * sub-element of the item/entry tag.
9108 *
9109 * See {@see SimplePie::get_feed_tags()} for a description of the return value
9110 *
9111 * @since 1.0
9112 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
9113 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
9114 * @param string $tag Tag name
9115 * @return array
9116 */
9117 public function get_item_tags($namespace, $tag)
f2f7b699 9118 {
a6e043ff 9119 if (isset($this->data['child'][$namespace][$tag]))
f2f7b699 9120 {
a6e043ff 9121 return $this->data['child'][$namespace][$tag];
f2f7b699
AD
9122 }
9123 else
9124 {
6d7d21a0 9125 return null;
f2f7b699
AD
9126 }
9127 }
9128
a6e043ff
AD
9129 /**
9130 * Get the base URL value from the parent feed
9131 *
9132 * Uses `<xml:base>`
9133 *
9134 * @param array $element
9135 * @return string
9136 */
9137 public function get_base($element = array())
9138 {
9139 return $this->feed->get_base($element);
9140 }
9141
9142 /**
9143 * Sanitize feed data
9144 *
9145 * @access private
9146 * @see SimplePie::sanitize()
9147 * @param string $data Data to sanitize
9148 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
9149 * @param string $base Base URL to resolve URLs against
9150 * @return string Sanitized data
9151 */
9152 public function sanitize($data, $type, $base = '')
f2f7b699 9153 {
a6e043ff
AD
9154 return $this->feed->sanitize($data, $type, $base);
9155 }
9156
9157 /**
9158 * Get the parent feed
9159 *
9160 * Note: this may not work as you think for multifeeds!
9161 *
9162 * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
9163 * @since 1.0
9164 * @return SimplePie
9165 */
9166 public function get_feed()
9167 {
9168 return $this->feed;
9169 }
9170
9171 /**
9172 * Get the unique identifier for the item
9173 *
9174 * This is usually used when writing code to check for new items in a feed.
9175 *
9176 * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
9177 * for RDF. If none of these are supplied (or `$hash` is true), creates an
9178 * MD5 hash based on the permalink and title. If either of those are not
9179 * supplied, creates a hash based on the full feed data.
9180 *
9181 * @since Beta 2
9182 * @param boolean $hash Should we force using a hash instead of the supplied ID?
9183 * @return string
9184 */
9185 public function get_id($hash = false)
9186 {
9187 if (!$hash)
f2f7b699 9188 {
a6e043ff
AD
9189 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
9190 {
9191 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9192 }
9193 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
9194 {
9195 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9196 }
9197 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9198 {
9199 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9200 }
9201 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
9202 {
9203 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9204 }
9205 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
9206 {
9207 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9208 }
9209 elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
9210 {
9211 return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
9212 }
9213 elseif (($return = $this->get_permalink()) !== null)
9214 {
9215 return $return;
9216 }
9217 elseif (($return = $this->get_title()) !== null)
9218 {
9219 return $return;
9220 }
9221 }
9222 if ($this->get_permalink() !== null || $this->get_title() !== null)
9223 {
9224 return md5($this->get_permalink() . $this->get_title());
f2f7b699 9225 }
6d7d21a0 9226 else
f2f7b699 9227 {
a6e043ff 9228 return md5(serialize($this->data));
f2f7b699 9229 }
f2f7b699 9230 }
6d7d21a0 9231
a6e043ff
AD
9232 /**
9233 * Get the title of the item
9234 *
9235 * Uses `<atom:title>`, `<title>` or `<dc:title>`
9236 *
9237 * @since Beta 2 (previously called `get_item_title` since 0.8)
9238 * @return string|null
9239 */
9240 public function get_title()
f2f7b699 9241 {
a6e043ff 9242 if (!isset($this->data['title']))
6d7d21a0 9243 {
a6e043ff 9244 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
6d7d21a0 9245 {
a6e043ff 9246 $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
6d7d21a0 9247 }
a6e043ff 9248 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
6d7d21a0 9249 {
a6e043ff 9250 $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
6d7d21a0 9251 }
a6e043ff 9252 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
6d7d21a0 9253 {
a6e043ff 9254 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6d7d21a0 9255 }
a6e043ff 9256 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
6d7d21a0 9257 {
a6e043ff 9258 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6d7d21a0 9259 }
a6e043ff 9260 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
6d7d21a0 9261 {
a6e043ff
AD
9262 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9263 }
9264 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
9265 {
9266 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9267 }
9268 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
9269 {
9270 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9271 }
9272 else
9273 {
9274 $this->data['title'] = null;
6d7d21a0
AD
9275 }
9276 }
a6e043ff 9277 return $this->data['title'];
6d7d21a0 9278 }
f2f7b699 9279
6d7d21a0 9280 /**
a6e043ff 9281 * Get the content for the item
6d7d21a0 9282 *
a6e043ff
AD
9283 * Prefers summaries over full content , but will return full content if a
9284 * summary does not exist.
6d7d21a0 9285 *
a6e043ff 9286 * To prefer full content instead, use {@see get_content}
6d7d21a0 9287 *
a6e043ff
AD
9288 * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
9289 * `<itunes:subtitle>`
6d7d21a0 9290 *
a6e043ff
AD
9291 * @since 0.8
9292 * @param boolean $description_only Should we avoid falling back to the content?
9293 * @return string|null
6d7d21a0 9294 */
a6e043ff
AD
9295 public function get_description($description_only = false)
9296 {
9297 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
9298 {
9299 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9300 }
9301 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
9302 {
9303 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9304 }
9305 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
9306 {
9307 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9308 }
9309 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
9310 {
9311 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9312 }
9313 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
9314 {
9315 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9316 }
9317 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
9318 {
9319 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9320 }
9321 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
9322 {
9323 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9324 }
9325 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
9326 {
9327 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9328 }
9329 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
9330 {
9331 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
9332 }
f2f7b699 9333
a6e043ff
AD
9334 elseif (!$description_only)
9335 {
9336 return $this->get_content(true);
9337 }
9338 else
9339 {
9340 return null;
9341 }
9342 }
f2f7b699 9343
6d7d21a0 9344 /**
a6e043ff 9345 * Get the content for the item
6d7d21a0 9346 *
a6e043ff
AD
9347 * Prefers full content over summaries, but will return a summary if full
9348 * content does not exist.
6d7d21a0 9349 *
a6e043ff 9350 * To prefer summaries instead, use {@see get_description}
6d7d21a0 9351 *
a6e043ff 9352 * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
6d7d21a0 9353 *
a6e043ff
AD
9354 * @since 1.0
9355 * @param boolean $content_only Should we avoid falling back to the description?
9356 * @return string|null
6d7d21a0 9357 */
a6e043ff 9358 public function get_content($content_only = false)
6d7d21a0 9359 {
a6e043ff 9360 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
6d7d21a0 9361 {
a6e043ff 9362 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
6d7d21a0 9363 }
a6e043ff 9364 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
6d7d21a0 9365 {
a6e043ff
AD
9366 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9367 }
9368 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
9369 {
9370 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9371 }
9372 elseif (!$content_only)
9373 {
9374 return $this->get_description(true);
6d7d21a0
AD
9375 }
9376 else
9377 {
a6e043ff 9378 return null;
6d7d21a0
AD
9379 }
9380 }
f2f7b699 9381
6d7d21a0 9382 /**
a6e043ff 9383 * Get a category for the item
6d7d21a0 9384 *
a6e043ff
AD
9385 * @since Beta 3 (previously called `get_categories()` since Beta 2)
9386 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
9387 * @return SimplePie_Category|null
6d7d21a0 9388 */
a6e043ff 9389 public function get_category($key = 0)
6d7d21a0 9390 {
a6e043ff
AD
9391 $categories = $this->get_categories();
9392 if (isset($categories[$key]))
9393 {
9394 return $categories[$key];
9395 }
9396 else
9397 {
9398 return null;
9399 }
6d7d21a0 9400 }
f2f7b699 9401
6d7d21a0 9402 /**
a6e043ff 9403 * Get all categories for the item
6d7d21a0 9404 *
a6e043ff 9405 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
6d7d21a0 9406 *
a6e043ff
AD
9407 * @since Beta 3
9408 * @return array|null List of {@see SimplePie_Category} objects
6d7d21a0 9409 */
a6e043ff 9410 public function get_categories()
6d7d21a0 9411 {
a6e043ff
AD
9412 $categories = array();
9413
9414 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
6d7d21a0 9415 {
a6e043ff
AD
9416 $term = null;
9417 $scheme = null;
9418 $label = null;
9419 if (isset($category['attribs']['']['term']))
6d7d21a0 9420 {
a6e043ff
AD
9421 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
9422 }
9423 if (isset($category['attribs']['']['scheme']))
9424 {
9425 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
9426 }
9427 if (isset($category['attribs']['']['label']))
9428 {
9429 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
9430 }
9431 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
9432 }
9433 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
9434 {
9435 // This is really the label, but keep this as the term also for BC.
9436 // Label will also work on retrieving because that falls back to term.
9437 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9438 if (isset($category['attribs']['']['domain']))
9439 {
9440 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0
AD
9441 }
9442 else
9443 {
a6e043ff 9444 $scheme = null;
6d7d21a0 9445 }
a6e043ff
AD
9446 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
9447 }
9448 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
9449 {
9450 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9451 }
9452 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
9453 {
9454 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9455 }
9456
9457 if (!empty($categories))
9458 {
9459 return array_unique($categories);
6d7d21a0
AD
9460 }
9461 else
9462 {
a6e043ff 9463 return null;
6d7d21a0
AD
9464 }
9465 }
f2f7b699 9466
6d7d21a0 9467 /**
a6e043ff 9468 * Get an author for the item
6d7d21a0 9469 *
a6e043ff
AD
9470 * @since Beta 2
9471 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
9472 * @return SimplePie_Author|null
6d7d21a0 9473 */
a6e043ff 9474 public function get_author($key = 0)
6d7d21a0 9475 {
a6e043ff
AD
9476 $authors = $this->get_authors();
9477 if (isset($authors[$key]))
6d7d21a0 9478 {
a6e043ff 9479 return $authors[$key];
6d7d21a0
AD
9480 }
9481 else
9482 {
a6e043ff 9483 return null;
6d7d21a0
AD
9484 }
9485 }
f2f7b699 9486
6d7d21a0 9487 /**
a6e043ff 9488 * Get a contributor for the item
6d7d21a0 9489 *
a6e043ff
AD
9490 * @since 1.1
9491 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
9492 * @return SimplePie_Author|null
6d7d21a0 9493 */
a6e043ff 9494 public function get_contributor($key = 0)
6d7d21a0 9495 {
a6e043ff
AD
9496 $contributors = $this->get_contributors();
9497 if (isset($contributors[$key]))
9498 {
9499 return $contributors[$key];
9500 }
9501 else
9502 {
9503 return null;
9504 }
6d7d21a0 9505 }
f2f7b699 9506
6d7d21a0 9507 /**
a6e043ff 9508 * Get all contributors for the item
6d7d21a0 9509 *
a6e043ff
AD
9510 * Uses `<atom:contributor>`
9511 *
9512 * @since 1.1
9513 * @return array|null List of {@see SimplePie_Author} objects
6d7d21a0 9514 */
a6e043ff 9515 public function get_contributors()
6d7d21a0 9516 {
a6e043ff
AD
9517 $contributors = array();
9518 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
6d7d21a0 9519 {
a6e043ff
AD
9520 $name = null;
9521 $uri = null;
9522 $email = null;
9523 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
6d7d21a0 9524 {
a6e043ff 9525 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 9526 }
a6e043ff 9527 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
6d7d21a0 9528 {
a6e043ff
AD
9529 $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]));
9530 }
9531 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9532 {
9533 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9534 }
9535 if ($name !== null || $email !== null || $uri !== null)
9536 {
9537 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
6d7d21a0
AD
9538 }
9539 }
a6e043ff 9540 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
6d7d21a0 9541 {
a6e043ff
AD
9542 $name = null;
9543 $url = null;
9544 $email = null;
9545 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9546 {
9547 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9548 }
9549 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9550 {
9551 $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]));
9552 }
9553 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9554 {
9555 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9556 }
9557 if ($name !== null || $email !== null || $url !== null)
9558 {
9559 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
9560 }
6d7d21a0 9561 }
a6e043ff
AD
9562
9563 if (!empty($contributors))
6d7d21a0 9564 {
a6e043ff 9565 return array_unique($contributors);
6d7d21a0
AD
9566 }
9567 else
9568 {
a6e043ff 9569 return null;
6d7d21a0
AD
9570 }
9571 }
f2f7b699 9572
6d7d21a0 9573 /**
a6e043ff 9574 * Get all authors for the item
6d7d21a0 9575 *
a6e043ff
AD
9576 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
9577 *
9578 * @since Beta 2
9579 * @return array|null List of {@see SimplePie_Author} objects
6d7d21a0 9580 */
a6e043ff 9581 public function get_authors()
6d7d21a0 9582 {
a6e043ff
AD
9583 $authors = array();
9584 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
6d7d21a0 9585 {
a6e043ff
AD
9586 $name = null;
9587 $uri = null;
9588 $email = null;
9589 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
6d7d21a0 9590 {
a6e043ff 9591 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 9592 }
a6e043ff 9593 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
6d7d21a0 9594 {
a6e043ff
AD
9595 $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]));
9596 }
9597 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9598 {
9599 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9600 }
9601 if ($name !== null || $email !== null || $uri !== null)
9602 {
9603 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
9604 }
9605 }
9606 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
9607 {
9608 $name = null;
9609 $url = null;
9610 $email = null;
9611 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9612 {
9613 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9614 }
9615 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9616 {
9617 $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]));
6d7d21a0 9618 }
a6e043ff
AD
9619 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9620 {
9621 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9622 }
9623 if ($name !== null || $email !== null || $url !== null)
9624 {
9625 $authors[] = $this->registry->create('Author', array($name, $url, $email));
9626 }
9627 }
9628 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
9629 {
9630 $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
9631 }
9632 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
9633 {
9634 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9635 }
9636 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
9637 {
9638 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9639 }
9640 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
9641 {
9642 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9643 }
9644
9645 if (!empty($authors))
9646 {
9647 return array_unique($authors);
9648 }
9649 elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
9650 {
9651 return $authors;
9652 }
9653 elseif ($authors = $this->feed->get_authors())
9654 {
9655 return $authors;
6d7d21a0
AD
9656 }
9657 else
9658 {
a6e043ff 9659 return null;
6d7d21a0
AD
9660 }
9661 }
f2f7b699 9662
6d7d21a0 9663 /**
a6e043ff 9664 * Get the copyright info for the item
6d7d21a0 9665 *
a6e043ff
AD
9666 * Uses `<atom:rights>` or `<dc:rights>`
9667 *
9668 * @since 1.1
9669 * @return string
6d7d21a0 9670 */
a6e043ff 9671 public function get_copyright()
6d7d21a0 9672 {
a6e043ff 9673 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
6d7d21a0 9674 {
a6e043ff
AD
9675 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9676 }
9677 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
9678 {
9679 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9680 }
9681 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
9682 {
9683 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9684 }
9685 else
9686 {
9687 return null;
9688 }
6d7d21a0 9689 }
f2f7b699 9690
6d7d21a0 9691 /**
a6e043ff 9692 * Get the posting date/time for the item
6d7d21a0 9693 *
a6e043ff
AD
9694 * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
9695 * `<atom:modified>`, `<pubDate>` or `<dc:date>`
9696 *
9697 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9698 * {@see get_gmdate}
9699 *
9700 * @since Beta 2 (previously called `get_item_date` since 0.8)
9701 *
9702 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9703 * @return int|string|null
6d7d21a0 9704 */
a6e043ff 9705 public function get_date($date_format = 'j F Y, g:i a')
6d7d21a0 9706 {
a6e043ff 9707 if (!isset($this->data['date']))
6d7d21a0 9708 {
a6e043ff
AD
9709 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
9710 {
9711 $this->data['date']['raw'] = $return[0]['data'];
9712 }
9713 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9714 {
9715 $this->data['date']['raw'] = $return[0]['data'];
9716 }
9717 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
9718 {
9719 $this->data['date']['raw'] = $return[0]['data'];
9720 }
9721 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
9722 {
9723 $this->data['date']['raw'] = $return[0]['data'];
9724 }
9725 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
9726 {
9727 $this->data['date']['raw'] = $return[0]['data'];
9728 }
9729 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
9730 {
9731 $this->data['date']['raw'] = $return[0]['data'];
9732 }
9733 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
9734 {
9735 $this->data['date']['raw'] = $return[0]['data'];
9736 }
9737 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
9738 {
9739 $this->data['date']['raw'] = $return[0]['data'];
9740 }
9741
9742 if (!empty($this->data['date']['raw']))
9743 {
9744 $parser = $this->registry->call('Parse_Date', 'get');
9745 $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
9746 }
9747 else
9748 {
9749 $this->data['date'] = null;
9750 }
6d7d21a0 9751 }
a6e043ff 9752 if ($this->data['date'])
6d7d21a0 9753 {
a6e043ff
AD
9754 $date_format = (string) $date_format;
9755 switch ($date_format)
6d7d21a0 9756 {
a6e043ff
AD
9757 case '':
9758 return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 9759
a6e043ff
AD
9760 case 'U':
9761 return $this->data['date']['parsed'];
f2f7b699 9762
6d7d21a0 9763 default:
a6e043ff 9764 return date($date_format, $this->data['date']['parsed']);
6d7d21a0
AD
9765 }
9766 }
a6e043ff
AD
9767 else
9768 {
9769 return null;
9770 }
6d7d21a0 9771 }
f2f7b699 9772
6d7d21a0 9773 /**
a6e043ff 9774 * Get the update date/time for the item
6d7d21a0 9775 *
a6e043ff 9776 * Uses `<atom:updated>`
6d7d21a0 9777 *
a6e043ff
AD
9778 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9779 * {@see get_gmdate}
9780 *
9781 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9782 * @return int|string|null
6d7d21a0 9783 */
a6e043ff 9784 public function get_updated_date($date_format = 'j F Y, g:i a')
6d7d21a0 9785 {
a6e043ff 9786 if (!isset($this->data['updated']))
6d7d21a0 9787 {
a6e043ff
AD
9788 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9789 {
9790 $this->data['updated']['raw'] = $return[0]['data'];
9791 }
9792
9793 if (!empty($this->data['updated']['raw']))
9794 {
9795 $parser = $this->registry->call('Parse_Date', 'get');
9796 $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
9797 }
9798 else
9799 {
9800 $this->data['updated'] = null;
9801 }
6d7d21a0 9802 }
a6e043ff 9803 if ($this->data['updated'])
6d7d21a0 9804 {
a6e043ff
AD
9805 $date_format = (string) $date_format;
9806 switch ($date_format)
6d7d21a0 9807 {
a6e043ff
AD
9808 case '':
9809 return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 9810
a6e043ff
AD
9811 case 'U':
9812 return $this->data['updated']['parsed'];
f2f7b699 9813
6d7d21a0 9814 default:
a6e043ff 9815 return date($date_format, $this->data['updated']['parsed']);
6d7d21a0
AD
9816 }
9817 }
a6e043ff
AD
9818 else
9819 {
9820 return null;
9821 }
6d7d21a0 9822 }
f2f7b699 9823
6d7d21a0 9824 /**
a6e043ff 9825 * Get the localized posting date/time for the item
6d7d21a0 9826 *
a6e043ff
AD
9827 * Returns the date formatted in the localized language. To display in
9828 * languages other than the server's default, you need to change the locale
9829 * with {@link http://php.net/setlocale setlocale()}. The available
9830 * localizations depend on which ones are installed on your web server.
9831 *
9832 * @since 1.0
9833 *
9834 * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
9835 * @return int|string|null
6d7d21a0 9836 */
a6e043ff 9837 public function get_local_date($date_format = '%c')
6d7d21a0 9838 {
a6e043ff
AD
9839 if (!$date_format)
9840 {
9841 return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
9842 }
9843 elseif (($date = $this->get_date('U')) !== null && $date !== false)
9844 {
9845 return strftime($date_format, $date);
9846 }
9847 else
9848 {
9849 return null;
9850 }
6d7d21a0 9851 }
f2f7b699 9852
6d7d21a0 9853 /**
a6e043ff 9854 * Get the posting date/time for the item (UTC time)
6d7d21a0 9855 *
a6e043ff
AD
9856 * @see get_date
9857 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9858 * @return int|string|null
6d7d21a0 9859 */
a6e043ff 9860 public function get_gmdate($date_format = 'j F Y, g:i a')
6d7d21a0 9861 {
a6e043ff
AD
9862 $date = $this->get_date('U');
9863 if ($date === null)
9864 {
9865 return null;
9866 }
9867
9868 return gmdate($date_format, $date);
6d7d21a0 9869 }
f2f7b699 9870
6d7d21a0 9871 /**
a6e043ff 9872 * Get the update date/time for the item (UTC time)
6d7d21a0 9873 *
a6e043ff
AD
9874 * @see get_updated_date
9875 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9876 * @return int|string|null
6d7d21a0 9877 */
a6e043ff 9878 public function get_updated_gmdate($date_format = 'j F Y, g:i a')
6d7d21a0 9879 {
a6e043ff
AD
9880 $date = $this->get_updated_date('U');
9881 if ($date === null)
9882 {
9883 return null;
9884 }
f954bd49 9885
a6e043ff
AD
9886 return gmdate($date_format, $date);
9887 }
f954bd49
AD
9888
9889 /**
a6e043ff 9890 * Get the permalink for the item
f954bd49 9891 *
a6e043ff
AD
9892 * Returns the first link available with a relationship of "alternate".
9893 * Identical to {@see get_link()} with key 0
f954bd49 9894 *
a6e043ff
AD
9895 * @see get_link
9896 * @since 0.8
9897 * @return string|null Permalink URL
f954bd49 9898 */
a6e043ff 9899 public function get_permalink()
f954bd49 9900 {
a6e043ff
AD
9901 $link = $this->get_link();
9902 $enclosure = $this->get_enclosure(0);
9903 if ($link !== null)
9904 {
9905 return $link;
9906 }
9907 elseif ($enclosure !== null)
9908 {
9909 return $enclosure->get_link();
9910 }
9911 else
9912 {
9913 return null;
9914 }
f954bd49
AD
9915 }
9916
9917 /**
a6e043ff 9918 * Get a single link for the item
f954bd49 9919 *
a6e043ff
AD
9920 * @since Beta 3
9921 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
9922 * @param string $rel The relationship of the link to return
9923 * @return string|null Link URL
f954bd49 9924 */
a6e043ff 9925 public function get_link($key = 0, $rel = 'alternate')
f954bd49 9926 {
a6e043ff
AD
9927 $links = $this->get_links($rel);
9928 if ($links[$key] !== null)
9929 {
9930 return $links[$key];
9931 }
9932 else
9933 {
9934 return null;
9935 }
f954bd49
AD
9936 }
9937
9938 /**
a6e043ff 9939 * Get all links for the item
f954bd49 9940 *
a6e043ff
AD
9941 * Uses `<atom:link>`, `<link>` or `<guid>`
9942 *
9943 * @since Beta 2
9944 * @param string $rel The relationship of links to return
9945 * @return array|null Links found for the item (strings)
f954bd49 9946 */
a6e043ff 9947 public function get_links($rel = 'alternate')
f954bd49 9948 {
a6e043ff 9949 if (!isset($this->data['links']))
f954bd49 9950 {
a6e043ff
AD
9951 $this->data['links'] = array();
9952 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
f954bd49 9953 {
a6e043ff
AD
9954 if (isset($link['attribs']['']['href']))
9955 {
9956 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9957 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
f954bd49 9958
a6e043ff
AD
9959 }
9960 }
9961 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
f954bd49 9962 {
a6e043ff
AD
9963 if (isset($link['attribs']['']['href']))
9964 {
9965 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9966 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
9967 }
f954bd49 9968 }
a6e043ff 9969 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
f954bd49 9970 {
a6e043ff 9971 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
f954bd49 9972 }
a6e043ff 9973 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
f954bd49 9974 {
a6e043ff
AD
9975 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9976 }
9977 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
9978 {
9979 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9980 }
9981 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9982 {
9983 if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
f954bd49 9984 {
a6e043ff 9985 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
f954bd49 9986 }
a6e043ff 9987 }
f954bd49 9988
a6e043ff
AD
9989 $keys = array_keys($this->data['links']);
9990 foreach ($keys as $key)
9991 {
9992 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
f954bd49 9993 {
a6e043ff
AD
9994 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
9995 {
9996 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
9997 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
9998 }
9999 else
10000 {
10001 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
10002 }
f954bd49 10003 }
a6e043ff 10004 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
f954bd49 10005 {
a6e043ff 10006 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
f954bd49 10007 }
a6e043ff 10008 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
f954bd49 10009 }
a6e043ff
AD
10010 }
10011 if (isset($this->data['links'][$rel]))
10012 {
10013 return $this->data['links'][$rel];
10014 }
10015 else
10016 {
10017 return null;
10018 }
10019 }
f954bd49 10020
a6e043ff
AD
10021 /**
10022 * Get an enclosure from the item
10023 *
10024 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10025 *
10026 * @since Beta 2
10027 * @todo Add ability to prefer one type of content over another (in a media group).
10028 * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
10029 * @return SimplePie_Enclosure|null
10030 */
10031 public function get_enclosure($key = 0, $prefer = null)
10032 {
10033 $enclosures = $this->get_enclosures();
10034 if (isset($enclosures[$key]))
10035 {
10036 return $enclosures[$key];
10037 }
10038 else
10039 {
10040 return null;
10041 }
10042 }
f954bd49 10043
a6e043ff
AD
10044 /**
10045 * Get all available enclosures (podcasts, etc.)
10046 *
10047 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10048 *
10049 * At this point, we're pretty much assuming that all enclosures for an item
10050 * are the same content. Anything else is too complicated to
10051 * properly support.
10052 *
10053 * @since Beta 2
10054 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
10055 * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
10056 * @return array|null List of SimplePie_Enclosure items
10057 */
10058 public function get_enclosures()
10059 {
10060 if (!isset($this->data['enclosures']))
10061 {
10062 $this->data['enclosures'] = array();
10063
10064 // Elements
10065 $captions_parent = null;
10066 $categories_parent = null;
10067 $copyrights_parent = null;
10068 $credits_parent = null;
10069 $description_parent = null;
10070 $duration_parent = null;
10071 $hashes_parent = null;
10072 $keywords_parent = null;
10073 $player_parent = null;
10074 $ratings_parent = null;
10075 $restrictions_parent = null;
10076 $thumbnails_parent = null;
10077 $title_parent = null;
10078
10079 // Let's do the channel and item-level ones first, and just re-use them if we need to.
10080 $parent = $this->get_feed();
10081
10082 // CAPTIONS
10083 if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10084 {
10085 foreach ($captions as $caption)
f954bd49 10086 {
a6e043ff
AD
10087 $caption_type = null;
10088 $caption_lang = null;
10089 $caption_startTime = null;
10090 $caption_endTime = null;
10091 $caption_text = null;
10092 if (isset($caption['attribs']['']['type']))
10093 {
10094 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10095 }
10096 if (isset($caption['attribs']['']['lang']))
10097 {
10098 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10099 }
10100 if (isset($caption['attribs']['']['start']))
10101 {
10102 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10103 }
10104 if (isset($caption['attribs']['']['end']))
10105 {
10106 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10107 }
10108 if (isset($caption['data']))
10109 {
10110 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10111 }
10112 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
f954bd49 10113 }
a6e043ff
AD
10114 }
10115 elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10116 {
10117 foreach ($captions as $caption)
f954bd49 10118 {
a6e043ff
AD
10119 $caption_type = null;
10120 $caption_lang = null;
10121 $caption_startTime = null;
10122 $caption_endTime = null;
10123 $caption_text = null;
10124 if (isset($caption['attribs']['']['type']))
10125 {
10126 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10127 }
10128 if (isset($caption['attribs']['']['lang']))
10129 {
10130 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10131 }
10132 if (isset($caption['attribs']['']['start']))
10133 {
10134 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10135 }
10136 if (isset($caption['attribs']['']['end']))
10137 {
10138 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10139 }
10140 if (isset($caption['data']))
10141 {
10142 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10143 }
10144 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
f954bd49
AD
10145 }
10146 }
a6e043ff 10147 if (is_array($captions_parent))
f954bd49 10148 {
a6e043ff
AD
10149 $captions_parent = array_values(array_unique($captions_parent));
10150 }
f954bd49 10151
a6e043ff
AD
10152 // CATEGORIES
10153 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
10154 {
10155 $term = null;
10156 $scheme = null;
10157 $label = null;
10158 if (isset($category['data']))
f954bd49 10159 {
a6e043ff
AD
10160 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10161 }
10162 if (isset($category['attribs']['']['scheme']))
10163 {
10164 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
f954bd49
AD
10165 }
10166 else
10167 {
a6e043ff
AD
10168 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10169 }
10170 if (isset($category['attribs']['']['label']))
10171 {
10172 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
f954bd49 10173 }
a6e043ff 10174 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
f954bd49 10175 }
a6e043ff 10176 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
f954bd49 10177 {
a6e043ff
AD
10178 $term = null;
10179 $scheme = null;
10180 $label = null;
10181 if (isset($category['data']))
f954bd49 10182 {
a6e043ff
AD
10183 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10184 }
10185 if (isset($category['attribs']['']['scheme']))
10186 {
10187 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
f954bd49
AD
10188 }
10189 else
10190 {
a6e043ff
AD
10191 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10192 }
10193 if (isset($category['attribs']['']['label']))
10194 {
10195 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
f954bd49 10196 }
a6e043ff 10197 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
f954bd49 10198 }
a6e043ff 10199 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
f954bd49 10200 {
a6e043ff
AD
10201 $term = null;
10202 $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
10203 $label = null;
10204 if (isset($category['attribs']['']['text']))
10205 {
10206 $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10207 }
10208 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10209
10210 if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
10211 {
10212 foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
10213 {
10214 if (isset($subcategory['attribs']['']['text']))
10215 {
10216 $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10217 }
10218 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10219 }
10220 }
f954bd49 10221 }
a6e043ff 10222 if (is_array($categories_parent))
f954bd49 10223 {
a6e043ff 10224 $categories_parent = array_values(array_unique($categories_parent));
f954bd49
AD
10225 }
10226
a6e043ff
AD
10227 // COPYRIGHT
10228 if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
f954bd49 10229 {
a6e043ff
AD
10230 $copyright_url = null;
10231 $copyright_label = null;
10232 if (isset($copyright[0]['attribs']['']['url']))
10233 {
10234 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10235 }
10236 if (isset($copyright[0]['data']))
10237 {
10238 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10239 }
10240 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10241 }
10242 elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
f954bd49 10243 {
a6e043ff
AD
10244 $copyright_url = null;
10245 $copyright_label = null;
10246 if (isset($copyright[0]['attribs']['']['url']))
10247 {
10248 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10249 }
10250 if (isset($copyright[0]['data']))
10251 {
10252 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10253 }
10254 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
f954bd49
AD
10255 }
10256
a6e043ff
AD
10257 // CREDITS
10258 if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
10259 {
10260 foreach ($credits as $credit)
a5ae3915 10261 {
a6e043ff
AD
10262 $credit_role = null;
10263 $credit_scheme = null;
10264 $credit_name = null;
10265 if (isset($credit['attribs']['']['role']))
10266 {
10267 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10268 }
10269 if (isset($credit['attribs']['']['scheme']))
10270 {
10271 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10272 }
10273 else
10274 {
10275 $credit_scheme = 'urn:ebu';
10276 }
10277 if (isset($credit['data']))
10278 {
10279 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10280 }
10281 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
a5ae3915 10282 }
6d7d21a0 10283 }
a6e043ff 10284 elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
6d7d21a0 10285 {
a6e043ff 10286 foreach ($credits as $credit)
6d7d21a0 10287 {
a6e043ff
AD
10288 $credit_role = null;
10289 $credit_scheme = null;
10290 $credit_name = null;
10291 if (isset($credit['attribs']['']['role']))
10292 {
10293 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10294 }
10295 if (isset($credit['attribs']['']['scheme']))
10296 {
10297 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10298 }
10299 else
10300 {
10301 $credit_scheme = 'urn:ebu';
10302 }
10303 if (isset($credit['data']))
10304 {
10305 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10306 }
10307 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
6d7d21a0
AD
10308 }
10309 }
a6e043ff 10310 if (is_array($credits_parent))
a5ae3915 10311 {
a6e043ff 10312 $credits_parent = array_values(array_unique($credits_parent));
a5ae3915
MK
10313 }
10314
a6e043ff
AD
10315 // DESCRIPTION
10316 if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
a5ae3915 10317 {
a6e043ff 10318 if (isset($description_parent[0]['data']))
a5ae3915 10319 {
a6e043ff 10320 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915
MK
10321 }
10322 }
a6e043ff 10323 elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
a5ae3915 10324 {
a6e043ff
AD
10325 if (isset($description_parent[0]['data']))
10326 {
10327 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10328 }
a5ae3915 10329 }
a6e043ff
AD
10330
10331 // DURATION
10332 if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
a5ae3915 10333 {
a6e043ff
AD
10334 $seconds = null;
10335 $minutes = null;
10336 $hours = null;
10337 if (isset($duration_parent[0]['data']))
10338 {
10339 $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10340 if (sizeof($temp) > 0)
10341 {
10342 $seconds = (int) array_pop($temp);
10343 }
10344 if (sizeof($temp) > 0)
10345 {
10346 $minutes = (int) array_pop($temp);
10347 $seconds += $minutes * 60;
10348 }
10349 if (sizeof($temp) > 0)
10350 {
10351 $hours = (int) array_pop($temp);
10352 $seconds += $hours * 3600;
10353 }
10354 unset($temp);
10355 $duration_parent = $seconds;
10356 }
a5ae3915 10357 }
a6e043ff
AD
10358
10359 // HASHES
10360 if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
a5ae3915 10361 {
a6e043ff
AD
10362 foreach ($hashes_iterator as $hash)
10363 {
10364 $value = null;
10365 $algo = null;
10366 if (isset($hash['data']))
10367 {
10368 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10369 }
10370 if (isset($hash['attribs']['']['algo']))
10371 {
10372 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10373 }
10374 else
10375 {
10376 $algo = 'md5';
10377 }
10378 $hashes_parent[] = $algo.':'.$value;
10379 }
a5ae3915 10380 }
a6e043ff 10381 elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
a5ae3915 10382 {
a6e043ff
AD
10383 foreach ($hashes_iterator as $hash)
10384 {
10385 $value = null;
10386 $algo = null;
10387 if (isset($hash['data']))
10388 {
10389 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10390 }
10391 if (isset($hash['attribs']['']['algo']))
10392 {
10393 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10394 }
10395 else
10396 {
10397 $algo = 'md5';
10398 }
10399 $hashes_parent[] = $algo.':'.$value;
10400 }
a5ae3915 10401 }
a6e043ff 10402 if (is_array($hashes_parent))
a5ae3915 10403 {
a6e043ff 10404 $hashes_parent = array_values(array_unique($hashes_parent));
a5ae3915
MK
10405 }
10406
a6e043ff
AD
10407 // KEYWORDS
10408 if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
a5ae3915 10409 {
a6e043ff 10410 if (isset($keywords[0]['data']))
a5ae3915 10411 {
a6e043ff
AD
10412 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10413 foreach ($temp as $word)
10414 {
10415 $keywords_parent[] = trim($word);
10416 }
a5ae3915 10417 }
a6e043ff
AD
10418 unset($temp);
10419 }
10420 elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10421 {
10422 if (isset($keywords[0]['data']))
a5ae3915 10423 {
a6e043ff
AD
10424 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10425 foreach ($temp as $word)
10426 {
10427 $keywords_parent[] = trim($word);
10428 }
a5ae3915 10429 }
a6e043ff
AD
10430 unset($temp);
10431 }
10432 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
10433 {
10434 if (isset($keywords[0]['data']))
a5ae3915 10435 {
a6e043ff
AD
10436 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10437 foreach ($temp as $word)
10438 {
10439 $keywords_parent[] = trim($word);
10440 }
a5ae3915 10441 }
a6e043ff
AD
10442 unset($temp);
10443 }
10444 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10445 {
10446 if (isset($keywords[0]['data']))
a5ae3915 10447 {
a6e043ff
AD
10448 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10449 foreach ($temp as $word)
10450 {
10451 $keywords_parent[] = trim($word);
10452 }
a5ae3915 10453 }
a6e043ff 10454 unset($temp);
a5ae3915 10455 }
a6e043ff 10456 if (is_array($keywords_parent))
a5ae3915 10457 {
a6e043ff 10458 $keywords_parent = array_values(array_unique($keywords_parent));
a5ae3915 10459 }
a6e043ff
AD
10460
10461 // PLAYER
10462 if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
a5ae3915 10463 {
a6e043ff
AD
10464 if (isset($player_parent[0]['attribs']['']['url']))
10465 {
10466 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10467 }
a5ae3915 10468 }
a6e043ff 10469 elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
a5ae3915 10470 {
a6e043ff
AD
10471 if (isset($player_parent[0]['attribs']['']['url']))
10472 {
10473 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10474 }
a5ae3915 10475 }
f2f7b699 10476
a6e043ff
AD
10477 // RATINGS
10478 if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
6d7d21a0 10479 {
a6e043ff
AD
10480 foreach ($ratings as $rating)
10481 {
10482 $rating_scheme = null;
10483 $rating_value = null;
10484 if (isset($rating['attribs']['']['scheme']))
10485 {
10486 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10487 }
10488 else
10489 {
10490 $rating_scheme = 'urn:simple';
10491 }
10492 if (isset($rating['data']))
10493 {
10494 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10495 }
10496 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10497 }
6d7d21a0 10498 }
a6e043ff 10499 elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
6d7d21a0 10500 {
a6e043ff 10501 foreach ($ratings as $rating)
6d7d21a0 10502 {
a6e043ff
AD
10503 $rating_scheme = 'urn:itunes';
10504 $rating_value = null;
10505 if (isset($rating['data']))
10506 {
10507 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10508 }
10509 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
6d7d21a0 10510 }
a6e043ff
AD
10511 }
10512 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
10513 {
10514 foreach ($ratings as $rating)
6d7d21a0 10515 {
a6e043ff
AD
10516 $rating_scheme = null;
10517 $rating_value = null;
10518 if (isset($rating['attribs']['']['scheme']))
10519 {
10520 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10521 }
10522 else
10523 {
10524 $rating_scheme = 'urn:simple';
10525 }
10526 if (isset($rating['data']))
6d7d21a0 10527 {
a6e043ff 10528 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 10529 }
a6e043ff 10530 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
a5ae3915 10531 }
a6e043ff
AD
10532 }
10533 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
10534 {
10535 foreach ($ratings as $rating)
a5ae3915 10536 {
a6e043ff
AD
10537 $rating_scheme = 'urn:itunes';
10538 $rating_value = null;
10539 if (isset($rating['data']))
6d7d21a0 10540 {
a6e043ff 10541 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 10542 }
a6e043ff 10543 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
6d7d21a0 10544 }
6d7d21a0 10545 }
a6e043ff 10546 if (is_array($ratings_parent))
6d7d21a0 10547 {
a6e043ff 10548 $ratings_parent = array_values(array_unique($ratings_parent));
6d7d21a0 10549 }
a5ae3915 10550
a6e043ff
AD
10551 // RESTRICTIONS
10552 if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
a5ae3915 10553 {
a6e043ff 10554 foreach ($restrictions as $restriction)
a5ae3915 10555 {
a6e043ff
AD
10556 $restriction_relationship = null;
10557 $restriction_type = null;
10558 $restriction_value = null;
10559 if (isset($restriction['attribs']['']['relationship']))
a5ae3915 10560 {
a6e043ff 10561 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915 10562 }
a6e043ff 10563 if (isset($restriction['attribs']['']['type']))
a5ae3915 10564 {
a6e043ff 10565 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915 10566 }
a6e043ff 10567 if (isset($restriction['data']))
a5ae3915 10568 {
a6e043ff 10569 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915 10570 }
a6e043ff
AD
10571 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10572 }
10573 }
10574 elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10575 {
10576 foreach ($restrictions as $restriction)
10577 {
10578 $restriction_relationship = 'allow';
10579 $restriction_type = null;
10580 $restriction_value = 'itunes';
10581 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
a5ae3915 10582 {
a6e043ff 10583 $restriction_relationship = 'deny';
a5ae3915 10584 }
a6e043ff 10585 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
a5ae3915
MK
10586 }
10587 }
a6e043ff 10588 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
a5ae3915 10589 {
a6e043ff 10590 foreach ($restrictions as $restriction)
a5ae3915 10591 {
a6e043ff
AD
10592 $restriction_relationship = null;
10593 $restriction_type = null;
10594 $restriction_value = null;
10595 if (isset($restriction['attribs']['']['relationship']))
a5ae3915 10596 {
a6e043ff
AD
10597 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
10598 }
10599 if (isset($restriction['attribs']['']['type']))
10600 {
10601 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915 10602 }
a6e043ff
AD
10603 if (isset($restriction['data']))
10604 {
10605 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10606 }
10607 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
a5ae3915 10608 }
a6e043ff
AD
10609 }
10610 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10611 {
10612 foreach ($restrictions as $restriction)
a5ae3915 10613 {
a6e043ff
AD
10614 $restriction_relationship = 'allow';
10615 $restriction_type = null;
10616 $restriction_value = 'itunes';
10617 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
10618 {
10619 $restriction_relationship = 'deny';
10620 }
10621 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
a5ae3915
MK
10622 }
10623 }
a6e043ff 10624 if (is_array($restrictions_parent))
a5ae3915 10625 {
a6e043ff 10626 $restrictions_parent = array_values(array_unique($restrictions_parent));
a5ae3915
MK
10627 }
10628 else
10629 {
a6e043ff 10630 $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
a5ae3915
MK
10631 }
10632
a6e043ff
AD
10633 // THUMBNAILS
10634 if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
a5ae3915 10635 {
a6e043ff 10636 foreach ($thumbnails as $thumbnail)
a5ae3915 10637 {
a6e043ff
AD
10638 if (isset($thumbnail['attribs']['']['url']))
10639 {
10640 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10641 }
a5ae3915 10642 }
a6e043ff
AD
10643 }
10644 elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
10645 {
10646 foreach ($thumbnails as $thumbnail)
a5ae3915 10647 {
a6e043ff
AD
10648 if (isset($thumbnail['attribs']['']['url']))
10649 {
10650 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10651 }
a5ae3915 10652 }
a6e043ff
AD
10653 }
10654
10655 // TITLES
10656 if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10657 {
10658 if (isset($title_parent[0]['data']))
a5ae3915 10659 {
a6e043ff 10660 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915 10661 }
a6e043ff
AD
10662 }
10663 elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10664 {
10665 if (isset($title_parent[0]['data']))
a5ae3915 10666 {
a6e043ff 10667 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915
MK
10668 }
10669 }
a5ae3915 10670
a6e043ff
AD
10671 // Clear the memory
10672 unset($parent);
a5ae3915 10673
a6e043ff
AD
10674 // Attributes
10675 $bitrate = null;
10676 $channels = null;
10677 $duration = null;
10678 $expression = null;
10679 $framerate = null;
10680 $height = null;
10681 $javascript = null;
10682 $lang = null;
10683 $length = null;
10684 $medium = null;
10685 $samplingrate = null;
10686 $type = null;
10687 $url = null;
10688 $width = null;
a5ae3915 10689
a6e043ff
AD
10690 // Elements
10691 $captions = null;
10692 $categories = null;
10693 $copyrights = null;
10694 $credits = null;
10695 $description = null;
10696 $hashes = null;
10697 $keywords = null;
10698 $player = null;
10699 $ratings = null;
10700 $restrictions = null;
10701 $thumbnails = null;
10702 $title = null;
f2f7b699 10703
a6e043ff
AD
10704 // If we have media:group tags, loop through them.
10705 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
6d7d21a0 10706 {
a6e043ff 10707 if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
6d7d21a0 10708 {
a6e043ff
AD
10709 // If we have media:content tags, loop through them.
10710 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
6d7d21a0 10711 {
a6e043ff 10712 if (isset($content['attribs']['']['url']))
6d7d21a0 10713 {
a6e043ff
AD
10714 // Attributes
10715 $bitrate = null;
10716 $channels = null;
10717 $duration = null;
10718 $expression = null;
10719 $framerate = null;
10720 $height = null;
10721 $javascript = null;
10722 $lang = null;
10723 $length = null;
10724 $medium = null;
10725 $samplingrate = null;
10726 $type = null;
10727 $url = null;
10728 $width = null;
f2f7b699 10729
a6e043ff
AD
10730 // Elements
10731 $captions = null;
10732 $categories = null;
10733 $copyrights = null;
10734 $credits = null;
10735 $description = null;
10736 $hashes = null;
10737 $keywords = null;
10738 $player = null;
10739 $ratings = null;
10740 $restrictions = null;
10741 $thumbnails = null;
10742 $title = null;
f2f7b699 10743
a6e043ff
AD
10744 // Start checking the attributes of media:content
10745 if (isset($content['attribs']['']['bitrate']))
10746 {
10747 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10748 }
10749 if (isset($content['attribs']['']['channels']))
10750 {
10751 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
10752 }
10753 if (isset($content['attribs']['']['duration']))
10754 {
10755 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
10756 }
10757 else
10758 {
10759 $duration = $duration_parent;
10760 }
10761 if (isset($content['attribs']['']['expression']))
10762 {
10763 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
10764 }
10765 if (isset($content['attribs']['']['framerate']))
10766 {
10767 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
10768 }
10769 if (isset($content['attribs']['']['height']))
10770 {
10771 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
10772 }
10773 if (isset($content['attribs']['']['lang']))
10774 {
10775 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10776 }
10777 if (isset($content['attribs']['']['fileSize']))
10778 {
10779 $length = ceil($content['attribs']['']['fileSize']);
10780 }
10781 if (isset($content['attribs']['']['medium']))
10782 {
10783 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
10784 }
10785 if (isset($content['attribs']['']['samplingrate']))
10786 {
10787 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10788 }
10789 if (isset($content['attribs']['']['type']))
10790 {
10791 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10792 }
10793 if (isset($content['attribs']['']['width']))
10794 {
10795 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
10796 }
10797 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10798
10799 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
10800
10801 // CAPTIONS
10802 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10803 {
10804 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10805 {
10806 $caption_type = null;
10807 $caption_lang = null;
10808 $caption_startTime = null;
10809 $caption_endTime = null;
10810 $caption_text = null;
10811 if (isset($caption['attribs']['']['type']))
10812 {
10813 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10814 }
10815 if (isset($caption['attribs']['']['lang']))
10816 {
10817 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10818 }
10819 if (isset($caption['attribs']['']['start']))
10820 {
10821 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10822 }
10823 if (isset($caption['attribs']['']['end']))
10824 {
10825 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10826 }
10827 if (isset($caption['data']))
10828 {
10829 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10830 }
10831 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10832 }
10833 if (is_array($captions))
10834 {
10835 $captions = array_values(array_unique($captions));
10836 }
10837 }
10838 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10839 {
10840 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10841 {
10842 $caption_type = null;
10843 $caption_lang = null;
10844 $caption_startTime = null;
10845 $caption_endTime = null;
10846 $caption_text = null;
10847 if (isset($caption['attribs']['']['type']))
10848 {
10849 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10850 }
10851 if (isset($caption['attribs']['']['lang']))
10852 {
10853 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10854 }
10855 if (isset($caption['attribs']['']['start']))
10856 {
10857 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10858 }
10859 if (isset($caption['attribs']['']['end']))
10860 {
10861 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10862 }
10863 if (isset($caption['data']))
10864 {
10865 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10866 }
10867 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10868 }
10869 if (is_array($captions))
10870 {
10871 $captions = array_values(array_unique($captions));
10872 }
10873 }
10874 else
10875 {
10876 $captions = $captions_parent;
10877 }
10878
10879 // CATEGORIES
10880 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10881 {
10882 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10883 {
10884 $term = null;
10885 $scheme = null;
10886 $label = null;
10887 if (isset($category['data']))
10888 {
10889 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10890 }
10891 if (isset($category['attribs']['']['scheme']))
10892 {
10893 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10894 }
10895 else
10896 {
10897 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10898 }
10899 if (isset($category['attribs']['']['label']))
10900 {
10901 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10902 }
10903 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10904 }
10905 }
10906 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10907 {
10908 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10909 {
10910 $term = null;
10911 $scheme = null;
10912 $label = null;
10913 if (isset($category['data']))
10914 {
10915 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10916 }
10917 if (isset($category['attribs']['']['scheme']))
10918 {
10919 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10920 }
10921 else
10922 {
10923 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10924 }
10925 if (isset($category['attribs']['']['label']))
10926 {
10927 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10928 }
10929 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10930 }
10931 }
10932 if (is_array($categories) && is_array($categories_parent))
10933 {
10934 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
10935 }
10936 elseif (is_array($categories))
10937 {
10938 $categories = array_values(array_unique($categories));
10939 }
10940 elseif (is_array($categories_parent))
10941 {
10942 $categories = array_values(array_unique($categories_parent));
10943 }
10944
10945 // COPYRIGHTS
10946 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10947 {
10948 $copyright_url = null;
10949 $copyright_label = null;
10950 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10951 {
10952 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10953 }
10954 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10955 {
10956 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10957 }
10958 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10959 }
10960 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10961 {
10962 $copyright_url = null;
10963 $copyright_label = null;
10964 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10965 {
10966 $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10967 }
10968 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10969 {
10970 $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10971 }
10972 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10973 }
10974 else
10975 {
10976 $copyrights = $copyrights_parent;
10977 }
10978
10979 // CREDITS
10980 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
10981 {
10982 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
10983 {
10984 $credit_role = null;
10985 $credit_scheme = null;
10986 $credit_name = null;
10987 if (isset($credit['attribs']['']['role']))
10988 {
10989 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10990 }
10991 if (isset($credit['attribs']['']['scheme']))
10992 {
10993 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10994 }
10995 else
10996 {
10997 $credit_scheme = 'urn:ebu';
10998 }
10999 if (isset($credit['data']))
11000 {
11001 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11002 }
11003 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11004 }
11005 if (is_array($credits))
11006 {
11007 $credits = array_values(array_unique($credits));
11008 }
11009 }
11010 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11011 {
11012 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11013 {
11014 $credit_role = null;
11015 $credit_scheme = null;
11016 $credit_name = null;
11017 if (isset($credit['attribs']['']['role']))
11018 {
11019 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11020 }
11021 if (isset($credit['attribs']['']['scheme']))
11022 {
11023 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11024 }
11025 else
11026 {
11027 $credit_scheme = 'urn:ebu';
11028 }
11029 if (isset($credit['data']))
11030 {
11031 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11032 }
11033 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11034 }
11035 if (is_array($credits))
11036 {
11037 $credits = array_values(array_unique($credits));
11038 }
11039 }
11040 else
11041 {
11042 $credits = $credits_parent;
11043 }
11044
11045 // DESCRIPTION
11046 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11047 {
11048 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11049 }
11050 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11051 {
11052 $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11053 }
11054 else
11055 {
11056 $description = $description_parent;
11057 }
11058
11059 // HASHES
11060 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11061 {
11062 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11063 {
11064 $value = null;
11065 $algo = null;
11066 if (isset($hash['data']))
11067 {
11068 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11069 }
11070 if (isset($hash['attribs']['']['algo']))
11071 {
11072 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11073 }
11074 else
11075 {
11076 $algo = 'md5';
11077 }
11078 $hashes[] = $algo.':'.$value;
11079 }
11080 if (is_array($hashes))
11081 {
11082 $hashes = array_values(array_unique($hashes));
11083 }
11084 }
11085 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11086 {
11087 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11088 {
11089 $value = null;
11090 $algo = null;
11091 if (isset($hash['data']))
11092 {
11093 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11094 }
11095 if (isset($hash['attribs']['']['algo']))
11096 {
11097 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11098 }
11099 else
11100 {
11101 $algo = 'md5';
11102 }
11103 $hashes[] = $algo.':'.$value;
11104 }
11105 if (is_array($hashes))
11106 {
11107 $hashes = array_values(array_unique($hashes));
11108 }
11109 }
11110 else
11111 {
11112 $hashes = $hashes_parent;
11113 }
11114
11115 // KEYWORDS
11116 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11117 {
11118 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11119 {
11120 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11121 foreach ($temp as $word)
11122 {
11123 $keywords[] = trim($word);
11124 }
11125 unset($temp);
11126 }
11127 if (is_array($keywords))
11128 {
11129 $keywords = array_values(array_unique($keywords));
11130 }
11131 }
11132 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11133 {
11134 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11135 {
11136 $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11137 foreach ($temp as $word)
11138 {
11139 $keywords[] = trim($word);
11140 }
11141 unset($temp);
11142 }
11143 if (is_array($keywords))
11144 {
11145 $keywords = array_values(array_unique($keywords));
11146 }
11147 }
11148 else
11149 {
11150 $keywords = $keywords_parent;
11151 }
11152
11153 // PLAYER
11154 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11155 {
11156 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11157 }
11158 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11159 {
11160 $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11161 }
11162 else
11163 {
11164 $player = $player_parent;
11165 }
11166
11167 // RATINGS
11168 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11169 {
11170 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11171 {
11172 $rating_scheme = null;
11173 $rating_value = null;
11174 if (isset($rating['attribs']['']['scheme']))
11175 {
11176 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11177 }
11178 else
11179 {
11180 $rating_scheme = 'urn:simple';
11181 }
11182 if (isset($rating['data']))
11183 {
11184 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11185 }
11186 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11187 }
11188 if (is_array($ratings))
11189 {
11190 $ratings = array_values(array_unique($ratings));
11191 }
11192 }
11193 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11194 {
11195 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11196 {
11197 $rating_scheme = null;
11198 $rating_value = null;
11199 if (isset($rating['attribs']['']['scheme']))
11200 {
11201 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11202 }
11203 else
11204 {
11205 $rating_scheme = 'urn:simple';
11206 }
11207 if (isset($rating['data']))
11208 {
11209 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11210 }
11211 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11212 }
11213 if (is_array($ratings))
11214 {
11215 $ratings = array_values(array_unique($ratings));
11216 }
11217 }
11218 else
11219 {
11220 $ratings = $ratings_parent;
11221 }
11222
11223 // RESTRICTIONS
11224 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11225 {
11226 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11227 {
11228 $restriction_relationship = null;
11229 $restriction_type = null;
11230 $restriction_value = null;
11231 if (isset($restriction['attribs']['']['relationship']))
11232 {
11233 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11234 }
11235 if (isset($restriction['attribs']['']['type']))
11236 {
11237 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11238 }
11239 if (isset($restriction['data']))
11240 {
11241 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11242 }
11243 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11244 }
11245 if (is_array($restrictions))
11246 {
11247 $restrictions = array_values(array_unique($restrictions));
11248 }
11249 }
11250 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11251 {
11252 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11253 {
11254 $restriction_relationship = null;
11255 $restriction_type = null;
11256 $restriction_value = null;
11257 if (isset($restriction['attribs']['']['relationship']))
11258 {
11259 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11260 }
11261 if (isset($restriction['attribs']['']['type']))
11262 {
11263 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11264 }
11265 if (isset($restriction['data']))
11266 {
11267 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11268 }
11269 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11270 }
11271 if (is_array($restrictions))
11272 {
11273 $restrictions = array_values(array_unique($restrictions));
11274 }
11275 }
11276 else
11277 {
11278 $restrictions = $restrictions_parent;
11279 }
11280
11281 // THUMBNAILS
11282 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11283 {
11284 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11285 {
11286 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11287 }
11288 if (is_array($thumbnails))
11289 {
11290 $thumbnails = array_values(array_unique($thumbnails));
11291 }
11292 }
11293 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11294 {
11295 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11296 {
11297 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11298 }
11299 if (is_array($thumbnails))
11300 {
11301 $thumbnails = array_values(array_unique($thumbnails));
11302 }
11303 }
11304 else
11305 {
11306 $thumbnails = $thumbnails_parent;
11307 }
11308
11309 // TITLES
11310 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11311 {
11312 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11313 }
11314 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11315 {
11316 $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11317 }
11318 else
11319 {
11320 $title = $title_parent;
11321 }
5b085627 11322
a6e043ff
AD
11323 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
11324 }
11325 }
11326 }
5b085627
MK
11327 }
11328
a6e043ff
AD
11329 // If we have standalone media:content tags, loop through them.
11330 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
5b085627 11331 {
a6e043ff
AD
11332 foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
11333 {
11334 if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11335 {
11336 // Attributes
11337 $bitrate = null;
11338 $channels = null;
11339 $duration = null;
11340 $expression = null;
11341 $framerate = null;
11342 $height = null;
11343 $javascript = null;
11344 $lang = null;
11345 $length = null;
11346 $medium = null;
11347 $samplingrate = null;
11348 $type = null;
11349 $url = null;
11350 $width = null;
5b085627 11351
a6e043ff
AD
11352 // Elements
11353 $captions = null;
11354 $categories = null;
11355 $copyrights = null;
11356 $credits = null;
11357 $description = null;
11358 $hashes = null;
11359 $keywords = null;
11360 $player = null;
11361 $ratings = null;
11362 $restrictions = null;
11363 $thumbnails = null;
11364 $title = null;
5b085627 11365
a6e043ff
AD
11366 // Start checking the attributes of media:content
11367 if (isset($content['attribs']['']['bitrate']))
11368 {
11369 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11370 }
11371 if (isset($content['attribs']['']['channels']))
11372 {
11373 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
11374 }
11375 if (isset($content['attribs']['']['duration']))
11376 {
11377 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
11378 }
11379 else
11380 {
11381 $duration = $duration_parent;
11382 }
11383 if (isset($content['attribs']['']['expression']))
11384 {
11385 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
11386 }
11387 if (isset($content['attribs']['']['framerate']))
11388 {
11389 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
11390 }
11391 if (isset($content['attribs']['']['height']))
11392 {
11393 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
11394 }
11395 if (isset($content['attribs']['']['lang']))
11396 {
11397 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11398 }
11399 if (isset($content['attribs']['']['fileSize']))
11400 {
11401 $length = ceil($content['attribs']['']['fileSize']);
11402 }
11403 if (isset($content['attribs']['']['medium']))
11404 {
11405 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
11406 }
11407 if (isset($content['attribs']['']['samplingrate']))
11408 {
11409 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11410 }
11411 if (isset($content['attribs']['']['type']))
11412 {
11413 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11414 }
11415 if (isset($content['attribs']['']['width']))
11416 {
11417 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
11418 }
11419 if (isset($content['attribs']['']['url']))
11420 {
11421 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11422 }
11423 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
f2f7b699 11424
a6e043ff
AD
11425 // CAPTIONS
11426 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
11427 {
11428 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
11429 {
11430 $caption_type = null;
11431 $caption_lang = null;
11432 $caption_startTime = null;
11433 $caption_endTime = null;
11434 $caption_text = null;
11435 if (isset($caption['attribs']['']['type']))
11436 {
11437 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11438 }
11439 if (isset($caption['attribs']['']['lang']))
11440 {
11441 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11442 }
11443 if (isset($caption['attribs']['']['start']))
11444 {
11445 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
11446 }
11447 if (isset($caption['attribs']['']['end']))
11448 {
11449 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
11450 }
11451 if (isset($caption['data']))
11452 {
11453 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11454 }
11455 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
11456 }
11457 if (is_array($captions))
11458 {
11459 $captions = array_values(array_unique($captions));
11460 }
11461 }
11462 else
11463 {
11464 $captions = $captions_parent;
11465 }
11466
11467 // CATEGORIES
11468 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
11469 {
11470 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
11471 {
11472 $term = null;
11473 $scheme = null;
11474 $label = null;
11475 if (isset($category['data']))
11476 {
11477 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11478 }
11479 if (isset($category['attribs']['']['scheme']))
11480 {
11481 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11482 }
11483 else
11484 {
11485 $scheme = 'http://search.yahoo.com/mrss/category_schema';
11486 }
11487 if (isset($category['attribs']['']['label']))
11488 {
11489 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
11490 }
11491 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
11492 }
11493 }
11494 if (is_array($categories) && is_array($categories_parent))
11495 {
11496 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
11497 }
11498 elseif (is_array($categories))
11499 {
11500 $categories = array_values(array_unique($categories));
11501 }
11502 elseif (is_array($categories_parent))
11503 {
11504 $categories = array_values(array_unique($categories_parent));
11505 }
11506 else
11507 {
11508 $categories = null;
11509 }
11510
11511 // COPYRIGHTS
11512 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
11513 {
11514 $copyright_url = null;
11515 $copyright_label = null;
11516 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
11517 {
11518 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
11519 }
11520 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
11521 {
11522 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11523 }
11524 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
11525 }
11526 else
11527 {
11528 $copyrights = $copyrights_parent;
11529 }
11530
11531 // CREDITS
11532 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11533 {
11534 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11535 {
11536 $credit_role = null;
11537 $credit_scheme = null;
11538 $credit_name = null;
11539 if (isset($credit['attribs']['']['role']))
11540 {
11541 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11542 }
11543 if (isset($credit['attribs']['']['scheme']))
11544 {
11545 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11546 }
11547 else
11548 {
11549 $credit_scheme = 'urn:ebu';
11550 }
11551 if (isset($credit['data']))
11552 {
11553 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11554 }
11555 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11556 }
11557 if (is_array($credits))
11558 {
11559 $credits = array_values(array_unique($credits));
11560 }
11561 }
11562 else
11563 {
11564 $credits = $credits_parent;
11565 }
f2f7b699 11566
a6e043ff
AD
11567 // DESCRIPTION
11568 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11569 {
11570 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11571 }
11572 else
11573 {
11574 $description = $description_parent;
11575 }
f2f7b699 11576
a6e043ff
AD
11577 // HASHES
11578 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11579 {
11580 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11581 {
11582 $value = null;
11583 $algo = null;
11584 if (isset($hash['data']))
11585 {
11586 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11587 }
11588 if (isset($hash['attribs']['']['algo']))
11589 {
11590 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11591 }
11592 else
11593 {
11594 $algo = 'md5';
11595 }
11596 $hashes[] = $algo.':'.$value;
11597 }
11598 if (is_array($hashes))
11599 {
11600 $hashes = array_values(array_unique($hashes));
11601 }
11602 }
11603 else
11604 {
11605 $hashes = $hashes_parent;
11606 }
f2f7b699 11607
a6e043ff
AD
11608 // KEYWORDS
11609 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11610 {
11611 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11612 {
11613 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11614 foreach ($temp as $word)
11615 {
11616 $keywords[] = trim($word);
11617 }
11618 unset($temp);
11619 }
11620 if (is_array($keywords))
11621 {
11622 $keywords = array_values(array_unique($keywords));
11623 }
11624 }
11625 else
11626 {
11627 $keywords = $keywords_parent;
11628 }
f2f7b699 11629
a6e043ff
AD
11630 // PLAYER
11631 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11632 {
11633 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11634 }
11635 else
11636 {
11637 $player = $player_parent;
11638 }
f2f7b699 11639
a6e043ff
AD
11640 // RATINGS
11641 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11642 {
11643 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11644 {
11645 $rating_scheme = null;
11646 $rating_value = null;
11647 if (isset($rating['attribs']['']['scheme']))
11648 {
11649 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11650 }
11651 else
11652 {
11653 $rating_scheme = 'urn:simple';
11654 }
11655 if (isset($rating['data']))
11656 {
11657 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11658 }
11659 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11660 }
11661 if (is_array($ratings))
11662 {
11663 $ratings = array_values(array_unique($ratings));
11664 }
11665 }
11666 else
11667 {
11668 $ratings = $ratings_parent;
11669 }
f2f7b699 11670
a6e043ff
AD
11671 // RESTRICTIONS
11672 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11673 {
11674 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11675 {
11676 $restriction_relationship = null;
11677 $restriction_type = null;
11678 $restriction_value = null;
11679 if (isset($restriction['attribs']['']['relationship']))
11680 {
11681 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11682 }
11683 if (isset($restriction['attribs']['']['type']))
11684 {
11685 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11686 }
11687 if (isset($restriction['data']))
11688 {
11689 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11690 }
11691 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11692 }
11693 if (is_array($restrictions))
11694 {
11695 $restrictions = array_values(array_unique($restrictions));
11696 }
11697 }
11698 else
11699 {
11700 $restrictions = $restrictions_parent;
11701 }
f2f7b699 11702
a6e043ff
AD
11703 // THUMBNAILS
11704 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11705 {
11706 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11707 {
11708 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11709 }
11710 if (is_array($thumbnails))
11711 {
11712 $thumbnails = array_values(array_unique($thumbnails));
11713 }
11714 }
11715 else
11716 {
11717 $thumbnails = $thumbnails_parent;
11718 }
f2f7b699 11719
a6e043ff
AD
11720 // TITLES
11721 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11722 {
11723 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11724 }
11725 else
11726 {
11727 $title = $title_parent;
11728 }
f2f7b699 11729
a6e043ff
AD
11730 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
11731 }
11732 }
11733 }
f2f7b699 11734
a6e043ff
AD
11735 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
11736 {
11737 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11738 {
11739 // Attributes
11740 $bitrate = null;
11741 $channels = null;
11742 $duration = null;
11743 $expression = null;
11744 $framerate = null;
11745 $height = null;
11746 $javascript = null;
11747 $lang = null;
11748 $length = null;
11749 $medium = null;
11750 $samplingrate = null;
11751 $type = null;
11752 $url = null;
11753 $width = null;
11754
11755 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11756 if (isset($link['attribs']['']['type']))
11757 {
11758 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11759 }
11760 if (isset($link['attribs']['']['length']))
11761 {
11762 $length = ceil($link['attribs']['']['length']);
11763 }
f954bd49 11764
a6e043ff
AD
11765 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11766 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
11767 }
11768 }
f954bd49 11769
a6e043ff
AD
11770 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
11771 {
11772 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11773 {
11774 // Attributes
11775 $bitrate = null;
11776 $channels = null;
11777 $duration = null;
11778 $expression = null;
11779 $framerate = null;
11780 $height = null;
11781 $javascript = null;
11782 $lang = null;
11783 $length = null;
11784 $medium = null;
11785 $samplingrate = null;
11786 $type = null;
11787 $url = null;
11788 $width = null;
f2f7b699 11789
a6e043ff
AD
11790 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11791 if (isset($link['attribs']['']['type']))
11792 {
11793 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11794 }
11795 if (isset($link['attribs']['']['length']))
11796 {
11797 $length = ceil($link['attribs']['']['length']);
11798 }
f954bd49 11799
a6e043ff
AD
11800 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11801 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
11802 }
11803 }
11804
11805 if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
6d7d21a0 11806 {
a6e043ff 11807 if (isset($enclosure[0]['attribs']['']['url']))
6d7d21a0 11808 {
a6e043ff
AD
11809 // Attributes
11810 $bitrate = null;
11811 $channels = null;
11812 $duration = null;
11813 $expression = null;
11814 $framerate = null;
11815 $height = null;
11816 $javascript = null;
11817 $lang = null;
11818 $length = null;
11819 $medium = null;
11820 $samplingrate = null;
11821 $type = null;
11822 $url = null;
11823 $width = null;
11824
11825 $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
11826 if (isset($enclosure[0]['attribs']['']['type']))
11827 {
11828 $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11829 }
11830 if (isset($enclosure[0]['attribs']['']['length']))
11831 {
11832 $length = ceil($enclosure[0]['attribs']['']['length']);
11833 }
11834
11835 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11836 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
6d7d21a0
AD
11837 }
11838 }
f2f7b699 11839
a6e043ff
AD
11840 if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
11841 {
11842 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11843 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
11844 }
11845
11846 $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
6d7d21a0 11847 }
a6e043ff 11848 if (!empty($this->data['enclosures']))
6d7d21a0 11849 {
a6e043ff 11850 return $this->data['enclosures'];
6d7d21a0 11851 }
f954bd49 11852 else
6d7d21a0 11853 {
a6e043ff 11854 return null;
6d7d21a0 11855 }
6d7d21a0 11856 }
f2f7b699 11857
5b085627 11858 /**
a6e043ff 11859 * Get the latitude coordinates for the item
5b085627 11860 *
a6e043ff 11861 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
5b085627 11862 *
a6e043ff
AD
11863 * Uses `<geo:lat>` or `<georss:point>`
11864 *
11865 * @since 1.0
11866 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11867 * @link http://www.georss.org/ GeoRSS
11868 * @return string|null
11869 */
11870 public function get_latitude()
11871 {
11872 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
11873 {
11874 return (float) $return[0]['data'];
11875 }
11876 elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
11877 {
11878 return (float) $match[1];
11879 }
11880 else
11881 {
11882 return null;
11883 }
11884 }
f954bd49 11885
a6e043ff
AD
11886 /**
11887 * Get the longitude coordinates for the item
11888 *
11889 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
11890 *
11891 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
11892 *
11893 * @since 1.0
11894 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11895 * @link http://www.georss.org/ GeoRSS
11896 * @return string|null
11897 */
11898 public function get_longitude()
11899 {
11900 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
11901 {
11902 return (float) $return[0]['data'];
11903 }
11904 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
11905 {
11906 return (float) $return[0]['data'];
11907 }
11908 elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
11909 {
11910 return (float) $match[2];
11911 }
11912 else
11913 {
11914 return null;
11915 }
11916 }
f954bd49 11917
a6e043ff
AD
11918 /**
11919 * Get the `<atom:source>` for the item
11920 *
11921 * @since 1.1
11922 * @return SimplePie_Source|null
11923 */
11924 public function get_source()
11925 {
11926 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
11927 {
11928 return $this->registry->create('Source', array($this, $return[0]));
11929 }
11930 else
11931 {
11932 return null;
11933 }
11934 }
11935}
f954bd49 11936
a6e043ff
AD
11937/**
11938 * Used for feed auto-discovery
11939 *
11940 *
11941 * This class can be overloaded with {@see SimplePie::set_locator_class()}
11942 *
11943 * @package SimplePie
11944 */
11945class SimplePie_Locator
11946{
11947 var $useragent;
11948 var $timeout;
11949 var $file;
11950 var $local = array();
11951 var $elsewhere = array();
11952 var $cached_entities = array();
11953 var $http_base;
11954 var $base;
11955 var $base_location = 0;
11956 var $checked_feeds = 0;
11957 var $max_checked_feeds = 10;
11958 protected $registry;
f954bd49 11959
a6e043ff
AD
11960 public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
11961 {
11962 $this->file = $file;
11963 $this->useragent = $useragent;
11964 $this->timeout = $timeout;
11965 $this->max_checked_feeds = $max_checked_feeds;
f954bd49 11966
a6e043ff
AD
11967 if (class_exists('DOMDocument'))
11968 {
11969 $this->dom = new DOMDocument();
f954bd49 11970
a6e043ff
AD
11971 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
11972 $this->dom->loadHTML($this->file->body);
11973 restore_error_handler();
11974 }
11975 else
11976 {
11977 $this->dom = null;
11978 }
11979 }
f954bd49 11980
a6e043ff
AD
11981 public function set_registry(SimplePie_Registry $registry)
11982 {
11983 $this->registry = $registry;
11984 }
f954bd49 11985
a6e043ff
AD
11986 public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
11987 {
11988 if ($this->is_feed($this->file))
11989 {
11990 return $this->file;
11991 }
f954bd49 11992
a6e043ff
AD
11993 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
11994 {
11995 $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
11996 if ($sniffer->get_type() !== 'text/html')
11997 {
11998 return null;
11999 }
12000 }
f954bd49 12001
a6e043ff
AD
12002 if ($type & ~SIMPLEPIE_LOCATOR_NONE)
12003 {
12004 $this->get_base();
12005 }
f954bd49 12006
a6e043ff
AD
12007 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
12008 {
12009 return $working[0];
12010 }
5b085627 12011
a6e043ff
AD
12012 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
12013 {
12014 if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
12015 {
12016 return $working;
12017 }
f954bd49 12018
a6e043ff
AD
12019 if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
12020 {
12021 return $working;
12022 }
f954bd49 12023
a6e043ff
AD
12024 if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
12025 {
12026 return $working;
12027 }
f954bd49 12028
a6e043ff
AD
12029 if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
12030 {
12031 return $working;
12032 }
12033 }
12034 return null;
12035 }
f954bd49 12036
a6e043ff
AD
12037 public function is_feed($file)
12038 {
12039 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
12040 {
12041 $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
12042 $sniffed = $sniffer->get_type();
12043 if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
12044 {
12045 return true;
12046 }
12047 else
12048 {
12049 return false;
12050 }
12051 }
12052 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
12053 {
12054 return true;
12055 }
12056 else
12057 {
12058 return false;
12059 }
12060 }
f954bd49 12061
a6e043ff
AD
12062 public function get_base()
12063 {
12064 if ($this->dom === null)
12065 {
12066 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12067 }
12068 $this->http_base = $this->file->url;
12069 $this->base = $this->http_base;
12070 $elements = $this->dom->getElementsByTagName('base');
12071 foreach ($elements as $element)
12072 {
12073 if ($element->hasAttribute('href'))
12074 {
12075 $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
12076 if ($base === false)
12077 {
12078 continue;
12079 }
12080 $this->base = $base;
12081 $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
12082 break;
12083 }
12084 }
12085 }
f954bd49 12086
a6e043ff
AD
12087 public function autodiscovery()
12088 {
12089 $done = array();
12090 $feeds = array();
12091 $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
12092 $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
12093 $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
f954bd49 12094
a6e043ff
AD
12095 if (!empty($feeds))
12096 {
12097 return array_values($feeds);
12098 }
12099 else
12100 {
12101 return null;
12102 }
12103 }
f954bd49 12104
a6e043ff
AD
12105 protected function search_elements_by_tag($name, &$done, $feeds)
12106 {
12107 if ($this->dom === null)
12108 {
12109 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12110 }
f954bd49 12111
a6e043ff
AD
12112 $links = $this->dom->getElementsByTagName($name);
12113 foreach ($links as $link)
12114 {
12115 if ($this->checked_feeds === $this->max_checked_feeds)
12116 {
12117 break;
12118 }
12119 if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
12120 {
12121 $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
12122 $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
f954bd49 12123
a6e043ff
AD
12124 if ($this->base_location < $line)
12125 {
12126 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12127 }
12128 else
12129 {
12130 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12131 }
12132 if ($href === false)
12133 {
12134 continue;
12135 }
f954bd49 12136
a6e043ff
AD
12137 if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
12138 {
12139 $this->checked_feeds++;
12140 $headers = array(
12141 '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',
12142 );
12143 $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
12144 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
12145 {
12146 $feeds[$href] = $feed;
12147 }
12148 }
12149 $done[] = $href;
12150 }
12151 }
f954bd49 12152
a6e043ff
AD
12153 return $feeds;
12154 }
f954bd49 12155
a6e043ff
AD
12156 public function get_links()
12157 {
12158 if ($this->dom === null)
12159 {
12160 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12161 }
f954bd49 12162
a6e043ff
AD
12163 $links = $this->dom->getElementsByTagName('a');
12164 foreach ($links as $link)
12165 {
12166 if ($link->hasAttribute('href'))
12167 {
12168 $href = trim($link->getAttribute('href'));
12169 $parsed = $this->registry->call('Misc', 'parse_url', array($href));
12170 if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
12171 {
12172 if ($this->base_location < $link->getLineNo())
12173 {
12174 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12175 }
12176 else
12177 {
12178 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12179 }
12180 if ($href === false)
12181 {
12182 continue;
12183 }
f954bd49 12184
a6e043ff 12185 $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
f954bd49 12186
a6e043ff
AD
12187 if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
12188 {
12189 $this->local[] = $href;
12190 }
12191 else
12192 {
12193 $this->elsewhere[] = $href;
12194 }
12195 }
12196 }
12197 }
12198 $this->local = array_unique($this->local);
12199 $this->elsewhere = array_unique($this->elsewhere);
12200 if (!empty($this->local) || !empty($this->elsewhere))
12201 {
12202 return true;
12203 }
12204 return null;
12205 }
f954bd49 12206
a6e043ff
AD
12207 public function extension(&$array)
12208 {
12209 foreach ($array as $key => $value)
12210 {
12211 if ($this->checked_feeds === $this->max_checked_feeds)
12212 {
12213 break;
12214 }
12215 if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
12216 {
12217 $this->checked_feeds++;
f954bd49 12218
a6e043ff
AD
12219 $headers = array(
12220 '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',
12221 );
12222 $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
12223 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
12224 {
12225 return $feed;
12226 }
12227 else
12228 {
12229 unset($array[$key]);
12230 }
12231 }
12232 }
12233 return null;
12234 }
f954bd49 12235
a6e043ff
AD
12236 public function body(&$array)
12237 {
12238 foreach ($array as $key => $value)
12239 {
12240 if ($this->checked_feeds === $this->max_checked_feeds)
12241 {
12242 break;
12243 }
12244 if (preg_match('/(rss|rdf|atom|xml)/i', $value))
12245 {
12246 $this->checked_feeds++;
12247 $headers = array(
12248 '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',
12249 );
12250 $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
12251 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
12252 {
12253 return $feed;
12254 }
12255 else
12256 {
12257 unset($array[$key]);
12258 }
12259 }
12260 }
12261 return null;
12262 }
12263}
f954bd49 12264
a6e043ff
AD
12265/**
12266 * Miscellanous utilities
12267 *
12268 * @package SimplePie
12269 */
12270class SimplePie_Misc
12271{
12272 public static function time_hms($seconds)
12273 {
12274 $time = '';
f954bd49 12275
a6e043ff
AD
12276 $hours = floor($seconds / 3600);
12277 $remainder = $seconds % 3600;
12278 if ($hours > 0)
12279 {
12280 $time .= $hours.':';
12281 }
f954bd49 12282
a6e043ff
AD
12283 $minutes = floor($remainder / 60);
12284 $seconds = $remainder % 60;
12285 if ($minutes < 10 && $hours > 0)
12286 {
12287 $minutes = '0' . $minutes;
12288 }
12289 if ($seconds < 10)
12290 {
12291 $seconds = '0' . $seconds;
12292 }
f954bd49 12293
a6e043ff
AD
12294 $time .= $minutes.':';
12295 $time .= $seconds;
f954bd49 12296
a6e043ff
AD
12297 return $time;
12298 }
f954bd49 12299
a6e043ff
AD
12300 public static function absolutize_url($relative, $base)
12301 {
12302 $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
12303 if ($iri === false)
12304 {
12305 return false;
12306 }
12307 return $iri->get_uri();
12308 }
f954bd49 12309
a6e043ff
AD
12310 /**
12311 * Get a HTML/XML element from a HTML string
12312 *
12313 * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
12314 * @param string $realname Element name (including namespace prefix if applicable)
12315 * @param string $string HTML document
12316 * @return array
12317 */
12318 public static function get_element($realname, $string)
12319 {
12320 $return = array();
12321 $name = preg_quote($realname, '/');
12322 if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
12323 {
12324 for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
12325 {
12326 $return[$i]['tag'] = $realname;
12327 $return[$i]['full'] = $matches[$i][0][0];
12328 $return[$i]['offset'] = $matches[$i][0][1];
12329 if (strlen($matches[$i][3][0]) <= 2)
12330 {
12331 $return[$i]['self_closing'] = true;
12332 }
12333 else
12334 {
12335 $return[$i]['self_closing'] = false;
12336 $return[$i]['content'] = $matches[$i][4][0];
12337 }
12338 $return[$i]['attribs'] = array();
12339 if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER))
12340 {
12341 for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
12342 {
12343 if (count($attribs[$j]) === 2)
12344 {
12345 $attribs[$j][2] = $attribs[$j][1];
12346 }
12347 $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
12348 }
12349 }
12350 }
12351 }
12352 return $return;
12353 }
f954bd49 12354
a6e043ff
AD
12355 public static function element_implode($element)
12356 {
12357 $full = "<$element[tag]";
12358 foreach ($element['attribs'] as $key => $value)
12359 {
12360 $key = strtolower($key);
12361 $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
12362 }
12363 if ($element['self_closing'])
12364 {
12365 $full .= ' />';
12366 }
12367 else
12368 {
12369 $full .= ">$element[content]</$element[tag]>";
12370 }
12371 return $full;
12372 }
f954bd49 12373
a6e043ff
AD
12374 public static function error($message, $level, $file, $line)
12375 {
12376 if ((ini_get('error_reporting') & $level) > 0)
12377 {
12378 switch ($level)
12379 {
12380 case E_USER_ERROR:
12381 $note = 'PHP Error';
12382 break;
12383 case E_USER_WARNING:
12384 $note = 'PHP Warning';
12385 break;
12386 case E_USER_NOTICE:
12387 $note = 'PHP Notice';
12388 break;
12389 default:
12390 $note = 'Unknown Error';
12391 break;
12392 }
f954bd49 12393
a6e043ff
AD
12394 $log_error = true;
12395 if (!function_exists('error_log'))
12396 {
12397 $log_error = false;
12398 }
f954bd49 12399
a6e043ff
AD
12400 $log_file = @ini_get('error_log');
12401 if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
12402 {
12403 $log_error = false;
12404 }
f954bd49 12405
a6e043ff
AD
12406 if ($log_error)
12407 {
12408 @error_log("$note: $message in $file on line $line", 0);
12409 }
12410 }
f954bd49 12411
a6e043ff
AD
12412 return $message;
12413 }
f954bd49 12414
a6e043ff
AD
12415 public static function fix_protocol($url, $http = 1)
12416 {
12417 $url = SimplePie_Misc::normalize_url($url);
12418 $parsed = SimplePie_Misc::parse_url($url);
12419 if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
12420 {
12421 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
12422 }
f954bd49 12423
a6e043ff
AD
12424 if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
12425 {
12426 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
12427 }
f954bd49 12428
a6e043ff
AD
12429 if ($http === 2 && $parsed['scheme'] !== '')
12430 {
12431 return "feed:$url";
12432 }
12433 elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
12434 {
12435 return substr_replace($url, 'podcast', 0, 4);
12436 }
12437 elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
12438 {
12439 return substr_replace($url, 'itpc', 0, 4);
12440 }
12441 else
12442 {
12443 return $url;
12444 }
12445 }
f954bd49 12446
a6e043ff
AD
12447 public static function parse_url($url)
12448 {
12449 $iri = new SimplePie_IRI($url);
12450 return array(
12451 'scheme' => (string) $iri->scheme,
12452 'authority' => (string) $iri->authority,
12453 'path' => (string) $iri->path,
12454 'query' => (string) $iri->query,
12455 'fragment' => (string) $iri->fragment
12456 );
12457 }
f954bd49 12458
a6e043ff
AD
12459 public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
12460 {
12461 $iri = new SimplePie_IRI('');
12462 $iri->scheme = $scheme;
12463 $iri->authority = $authority;
12464 $iri->path = $path;
12465 $iri->query = $query;
12466 $iri->fragment = $fragment;
12467 return $iri->get_uri();
12468 }
f954bd49 12469
a6e043ff
AD
12470 public static function normalize_url($url)
12471 {
12472 $iri = new SimplePie_IRI($url);
12473 return $iri->get_uri();
12474 }
f954bd49 12475
a6e043ff
AD
12476 public static function percent_encoding_normalization($match)
12477 {
12478 $integer = hexdec($match[1]);
12479 if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
12480 {
12481 return chr($integer);
12482 }
12483 else
12484 {
12485 return strtoupper($match[0]);
12486 }
12487 }
f954bd49 12488
a6e043ff
AD
12489 /**
12490 * Converts a Windows-1252 encoded string to a UTF-8 encoded string
12491 *
12492 * @static
12493 * @param string $string Windows-1252 encoded string
12494 * @return string UTF-8 encoded string
12495 */
12496 public static function windows_1252_to_utf8($string)
12497 {
12498 static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
5b085627 12499
a6e043ff
AD
12500 return strtr($string, $convert_table);
12501 }
f954bd49 12502
a6e043ff
AD
12503 /**
12504 * Change a string from one encoding to another
12505 *
12506 * @param string $data Raw data in $input encoding
12507 * @param string $input Encoding of $data
12508 * @param string $output Encoding you want
12509 * @return string|boolean False if we can't convert it
12510 */
12511 public static function change_encoding($data, $input, $output)
12512 {
12513 $input = SimplePie_Misc::encoding($input);
12514 $output = SimplePie_Misc::encoding($output);
f954bd49 12515
a6e043ff
AD
12516 // We fail to fail on non US-ASCII bytes
12517 if ($input === 'US-ASCII')
12518 {
12519 static $non_ascii_octects = '';
12520 if (!$non_ascii_octects)
12521 {
12522 for ($i = 0x80; $i <= 0xFF; $i++)
12523 {
12524 $non_ascii_octects .= chr($i);
12525 }
12526 }
12527 $data = substr($data, 0, strcspn($data, $non_ascii_octects));
12528 }
f954bd49 12529
a6e043ff
AD
12530 // This is first, as behaviour of this is completely predictable
12531 if ($input === 'windows-1252' && $output === 'UTF-8')
12532 {
12533 return SimplePie_Misc::windows_1252_to_utf8($data);
12534 }
12535 // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
12536 elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
12537 {
12538 return $return;
12539 }
12540 // This is last, as behaviour of this varies with OS userland and PHP version
12541 elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
12542 {
12543 return $return;
12544 }
12545 // If we can't do anything, just fail
12546 else
12547 {
12548 return false;
12549 }
12550 }
f954bd49 12551
a6e043ff
AD
12552 protected static function change_encoding_mbstring($data, $input, $output)
12553 {
12554 if ($input === 'windows-949')
12555 {
12556 $input = 'EUC-KR';
12557 }
12558 if ($output === 'windows-949')
12559 {
12560 $output = 'EUC-KR';
12561 }
12562 if ($input === 'Windows-31J')
12563 {
12564 $input = 'SJIS';
12565 }
12566 if ($output === 'Windows-31J')
12567 {
12568 $output = 'SJIS';
12569 }
f954bd49 12570
a6e043ff
AD
12571 // Check that the encoding is supported
12572 if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
12573 {
12574 return false;
12575 }
12576 if (!in_array($input, mb_list_encodings()))
12577 {
12578 return false;
12579 }
f954bd49 12580
a6e043ff
AD
12581 // Let's do some conversion
12582 if ($return = @mb_convert_encoding($data, $output, $input))
12583 {
12584 return $return;
12585 }
f954bd49 12586
a6e043ff
AD
12587 return false;
12588 }
f954bd49 12589
a6e043ff
AD
12590 protected static function change_encoding_iconv($data, $input, $output)
12591 {
12592 return @iconv($input, $output, $data);
12593 }
f954bd49 12594
a6e043ff
AD
12595 /**
12596 * Normalize an encoding name
12597 *
12598 * This is automatically generated by create.php
12599 *
12600 * To generate it, run `php create.php` on the command line, and copy the
12601 * output to replace this function.
12602 *
12603 * @param string $charset Character set to standardise
12604 * @return string Standardised name
12605 */
12606 public static function encoding($charset)
12607 {
12608 // Normalization from UTS #22
12609 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
12610 {
12611 case 'adobestandardencoding':
12612 case 'csadobestandardencoding':
12613 return 'Adobe-Standard-Encoding';
f954bd49 12614
a6e043ff
AD
12615 case 'adobesymbolencoding':
12616 case 'cshppsmath':
12617 return 'Adobe-Symbol-Encoding';
f954bd49 12618
a6e043ff
AD
12619 case 'ami1251':
12620 case 'amiga1251':
12621 return 'Amiga-1251';
f954bd49 12622
a6e043ff
AD
12623 case 'ansix31101983':
12624 case 'csat5001983':
12625 case 'csiso99naplps':
12626 case 'isoir99':
12627 case 'naplps':
12628 return 'ANSI_X3.110-1983';
f954bd49 12629
a6e043ff
AD
12630 case 'arabic7':
12631 case 'asmo449':
12632 case 'csiso89asmo449':
12633 case 'iso9036':
12634 case 'isoir89':
12635 return 'ASMO_449';
f954bd49 12636
a6e043ff
AD
12637 case 'big5':
12638 case 'csbig5':
12639 return 'Big5';
f954bd49 12640
a6e043ff
AD
12641 case 'big5hkscs':
12642 return 'Big5-HKSCS';
f954bd49 12643
a6e043ff
AD
12644 case 'bocu1':
12645 case 'csbocu1':
12646 return 'BOCU-1';
f954bd49 12647
a6e043ff
AD
12648 case 'brf':
12649 case 'csbrf':
12650 return 'BRF';
5b085627 12651
a6e043ff
AD
12652 case 'bs4730':
12653 case 'csiso4unitedkingdom':
12654 case 'gb':
12655 case 'iso646gb':
12656 case 'isoir4':
12657 case 'uk':
12658 return 'BS_4730';
f954bd49 12659
a6e043ff
AD
12660 case 'bsviewdata':
12661 case 'csiso47bsviewdata':
12662 case 'isoir47':
12663 return 'BS_viewdata';
f954bd49 12664
a6e043ff
AD
12665 case 'cesu8':
12666 case 'cscesu8':
12667 return 'CESU-8';
5b085627 12668
a6e043ff
AD
12669 case 'ca':
12670 case 'csa71':
12671 case 'csaz243419851':
12672 case 'csiso121canadian1':
12673 case 'iso646ca':
12674 case 'isoir121':
12675 return 'CSA_Z243.4-1985-1';
5b085627 12676
a6e043ff
AD
12677 case 'csa72':
12678 case 'csaz243419852':
12679 case 'csiso122canadian2':
12680 case 'iso646ca2':
12681 case 'isoir122':
12682 return 'CSA_Z243.4-1985-2';
5b085627 12683
a6e043ff
AD
12684 case 'csaz24341985gr':
12685 case 'csiso123csaz24341985gr':
12686 case 'isoir123':
12687 return 'CSA_Z243.4-1985-gr';
5b085627 12688
a6e043ff
AD
12689 case 'csiso139csn369103':
12690 case 'csn369103':
12691 case 'isoir139':
12692 return 'CSN_369103';
5b085627 12693
a6e043ff
AD
12694 case 'csdecmcs':
12695 case 'dec':
12696 case 'decmcs':
12697 return 'DEC-MCS';
5b085627 12698
a6e043ff
AD
12699 case 'csiso21german':
12700 case 'de':
12701 case 'din66003':
12702 case 'iso646de':
12703 case 'isoir21':
12704 return 'DIN_66003';
5b085627 12705
a6e043ff
AD
12706 case 'csdkus':
12707 case 'dkus':
12708 return 'dk-us';
5b085627 12709
a6e043ff
AD
12710 case 'csiso646danish':
12711 case 'dk':
12712 case 'ds2089':
12713 case 'iso646dk':
12714 return 'DS_2089';
5b085627 12715
a6e043ff
AD
12716 case 'csibmebcdicatde':
12717 case 'ebcdicatde':
12718 return 'EBCDIC-AT-DE';
5b085627 12719
a6e043ff
AD
12720 case 'csebcdicatdea':
12721 case 'ebcdicatdea':
12722 return 'EBCDIC-AT-DE-A';
f954bd49 12723
a6e043ff
AD
12724 case 'csebcdiccafr':
12725 case 'ebcdiccafr':
12726 return 'EBCDIC-CA-FR';
f954bd49 12727
a6e043ff
AD
12728 case 'csebcdicdkno':
12729 case 'ebcdicdkno':
12730 return 'EBCDIC-DK-NO';
f954bd49 12731
a6e043ff
AD
12732 case 'csebcdicdknoa':
12733 case 'ebcdicdknoa':
12734 return 'EBCDIC-DK-NO-A';
f954bd49 12735
a6e043ff
AD
12736 case 'csebcdices':
12737 case 'ebcdices':
12738 return 'EBCDIC-ES';
f954bd49 12739
a6e043ff
AD
12740 case 'csebcdicesa':
12741 case 'ebcdicesa':
12742 return 'EBCDIC-ES-A';
f954bd49 12743
a6e043ff
AD
12744 case 'csebcdicess':
12745 case 'ebcdicess':
12746 return 'EBCDIC-ES-S';
f954bd49 12747
a6e043ff
AD
12748 case 'csebcdicfise':
12749 case 'ebcdicfise':
12750 return 'EBCDIC-FI-SE';
f954bd49 12751
a6e043ff
AD
12752 case 'csebcdicfisea':
12753 case 'ebcdicfisea':
12754 return 'EBCDIC-FI-SE-A';
f954bd49 12755
a6e043ff
AD
12756 case 'csebcdicfr':
12757 case 'ebcdicfr':
12758 return 'EBCDIC-FR';
f954bd49 12759
a6e043ff
AD
12760 case 'csebcdicit':
12761 case 'ebcdicit':
12762 return 'EBCDIC-IT';
f954bd49 12763
a6e043ff
AD
12764 case 'csebcdicpt':
12765 case 'ebcdicpt':
12766 return 'EBCDIC-PT';
f954bd49 12767
a6e043ff
AD
12768 case 'csebcdicuk':
12769 case 'ebcdicuk':
12770 return 'EBCDIC-UK';
f954bd49 12771
a6e043ff
AD
12772 case 'csebcdicus':
12773 case 'ebcdicus':
12774 return 'EBCDIC-US';
f954bd49 12775
a6e043ff
AD
12776 case 'csiso111ecmacyrillic':
12777 case 'ecmacyrillic':
12778 case 'isoir111':
12779 case 'koi8e':
12780 return 'ECMA-cyrillic';
f954bd49 12781
a6e043ff
AD
12782 case 'csiso17spanish':
12783 case 'es':
12784 case 'iso646es':
12785 case 'isoir17':
12786 return 'ES';
f954bd49 12787
a6e043ff
AD
12788 case 'csiso85spanish2':
12789 case 'es2':
12790 case 'iso646es2':
12791 case 'isoir85':
12792 return 'ES2';
f954bd49 12793
a6e043ff
AD
12794 case 'cseucpkdfmtjapanese':
12795 case 'eucjp':
12796 case 'extendedunixcodepackedformatforjapanese':
12797 return 'EUC-JP';
f954bd49 12798
a6e043ff
AD
12799 case 'cseucfixwidjapanese':
12800 case 'extendedunixcodefixedwidthforjapanese':
12801 return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
f954bd49 12802
a6e043ff
AD
12803 case 'gb18030':
12804 return 'GB18030';
f954bd49 12805
a6e043ff
AD
12806 case 'chinese':
12807 case 'cp936':
12808 case 'csgb2312':
12809 case 'csiso58gb231280':
12810 case 'gb2312':
12811 case 'gb231280':
12812 case 'gbk':
12813 case 'isoir58':
12814 case 'ms936':
12815 case 'windows936':
12816 return 'GBK';
f954bd49 12817
a6e043ff
AD
12818 case 'cn':
12819 case 'csiso57gb1988':
12820 case 'gb198880':
12821 case 'iso646cn':
12822 case 'isoir57':
12823 return 'GB_1988-80';
f954bd49 12824
a6e043ff
AD
12825 case 'csiso153gost1976874':
12826 case 'gost1976874':
12827 case 'isoir153':
12828 case 'stsev35888':
12829 return 'GOST_19768-74';
f954bd49 12830
a6e043ff
AD
12831 case 'csiso150':
12832 case 'csiso150greekccitt':
12833 case 'greekccitt':
12834 case 'isoir150':
12835 return 'greek-ccitt';
f954bd49 12836
a6e043ff
AD
12837 case 'csiso88greek7':
12838 case 'greek7':
12839 case 'isoir88':
12840 return 'greek7';
f954bd49 12841
a6e043ff
AD
12842 case 'csiso18greek7old':
12843 case 'greek7old':
12844 case 'isoir18':
12845 return 'greek7-old';
f954bd49 12846
a6e043ff
AD
12847 case 'cshpdesktop':
12848 case 'hpdesktop':
12849 return 'HP-DeskTop';
f954bd49 12850
a6e043ff
AD
12851 case 'cshplegal':
12852 case 'hplegal':
12853 return 'HP-Legal';
f954bd49 12854
a6e043ff
AD
12855 case 'cshpmath8':
12856 case 'hpmath8':
12857 return 'HP-Math8';
f954bd49 12858
a6e043ff
AD
12859 case 'cshppifont':
12860 case 'hppifont':
12861 return 'HP-Pi-font';
f954bd49 12862
a6e043ff
AD
12863 case 'cshproman8':
12864 case 'hproman8':
12865 case 'r8':
12866 case 'roman8':
12867 return 'hp-roman8';
f954bd49 12868
a6e043ff
AD
12869 case 'hzgb2312':
12870 return 'HZ-GB-2312';
f954bd49 12871
a6e043ff
AD
12872 case 'csibmsymbols':
12873 case 'ibmsymbols':
12874 return 'IBM-Symbols';
f954bd49 12875
a6e043ff
AD
12876 case 'csibmthai':
12877 case 'ibmthai':
12878 return 'IBM-Thai';
12879
12880 case 'cp37':
12881 case 'csibm37':
12882 case 'ebcdiccpca':
12883 case 'ebcdiccpnl':
12884 case 'ebcdiccpus':
12885 case 'ebcdiccpwt':
12886 case 'ibm37':
12887 return 'IBM037';
f954bd49 12888
a6e043ff
AD
12889 case 'cp38':
12890 case 'csibm38':
12891 case 'ebcdicint':
12892 case 'ibm38':
12893 return 'IBM038';
f954bd49 12894
a6e043ff
AD
12895 case 'cp273':
12896 case 'csibm273':
12897 case 'ibm273':
12898 return 'IBM273';
f954bd49 12899
a6e043ff
AD
12900 case 'cp274':
12901 case 'csibm274':
12902 case 'ebcdicbe':
12903 case 'ibm274':
12904 return 'IBM274';
f954bd49 12905
a6e043ff
AD
12906 case 'cp275':
12907 case 'csibm275':
12908 case 'ebcdicbr':
12909 case 'ibm275':
12910 return 'IBM275';
f954bd49 12911
a6e043ff
AD
12912 case 'csibm277':
12913 case 'ebcdiccpdk':
12914 case 'ebcdiccpno':
12915 case 'ibm277':
12916 return 'IBM277';
f954bd49 12917
a6e043ff
AD
12918 case 'cp278':
12919 case 'csibm278':
12920 case 'ebcdiccpfi':
12921 case 'ebcdiccpse':
12922 case 'ibm278':
12923 return 'IBM278';
f954bd49 12924
a6e043ff
AD
12925 case 'cp280':
12926 case 'csibm280':
12927 case 'ebcdiccpit':
12928 case 'ibm280':
12929 return 'IBM280';
f954bd49 12930
a6e043ff
AD
12931 case 'cp281':
12932 case 'csibm281':
12933 case 'ebcdicjpe':
12934 case 'ibm281':
12935 return 'IBM281';
f954bd49 12936
a6e043ff
AD
12937 case 'cp284':
12938 case 'csibm284':
12939 case 'ebcdiccpes':
12940 case 'ibm284':
12941 return 'IBM284';
f954bd49 12942
a6e043ff
AD
12943 case 'cp285':
12944 case 'csibm285':
12945 case 'ebcdiccpgb':
12946 case 'ibm285':
12947 return 'IBM285';
f954bd49 12948
a6e043ff
AD
12949 case 'cp290':
12950 case 'csibm290':
12951 case 'ebcdicjpkana':
12952 case 'ibm290':
12953 return 'IBM290';
f954bd49 12954
a6e043ff
AD
12955 case 'cp297':
12956 case 'csibm297':
12957 case 'ebcdiccpfr':
12958 case 'ibm297':
12959 return 'IBM297';
f954bd49 12960
a6e043ff
AD
12961 case 'cp420':
12962 case 'csibm420':
12963 case 'ebcdiccpar1':
12964 case 'ibm420':
12965 return 'IBM420';
f954bd49 12966
a6e043ff
AD
12967 case 'cp423':
12968 case 'csibm423':
12969 case 'ebcdiccpgr':
12970 case 'ibm423':
12971 return 'IBM423';
f954bd49 12972
a6e043ff
AD
12973 case 'cp424':
12974 case 'csibm424':
12975 case 'ebcdiccphe':
12976 case 'ibm424':
12977 return 'IBM424';
f954bd49 12978
a6e043ff
AD
12979 case '437':
12980 case 'cp437':
12981 case 'cspc8codepage437':
12982 case 'ibm437':
12983 return 'IBM437';
f954bd49 12984
a6e043ff
AD
12985 case 'cp500':
12986 case 'csibm500':
12987 case 'ebcdiccpbe':
12988 case 'ebcdiccpch':
12989 case 'ibm500':
12990 return 'IBM500';
f954bd49 12991
a6e043ff
AD
12992 case 'cp775':
12993 case 'cspc775baltic':
12994 case 'ibm775':
12995 return 'IBM775';
f954bd49 12996
a6e043ff
AD
12997 case '850':
12998 case 'cp850':
12999 case 'cspc850multilingual':
13000 case 'ibm850':
13001 return 'IBM850';
f954bd49 13002
a6e043ff
AD
13003 case '851':
13004 case 'cp851':
13005 case 'csibm851':
13006 case 'ibm851':
13007 return 'IBM851';
f954bd49 13008
a6e043ff
AD
13009 case '852':
13010 case 'cp852':
13011 case 'cspcp852':
13012 case 'ibm852':
13013 return 'IBM852';
f954bd49 13014
a6e043ff
AD
13015 case '855':
13016 case 'cp855':
13017 case 'csibm855':
13018 case 'ibm855':
13019 return 'IBM855';
f954bd49 13020
a6e043ff
AD
13021 case '857':
13022 case 'cp857':
13023 case 'csibm857':
13024 case 'ibm857':
13025 return 'IBM857';
f954bd49 13026
a6e043ff
AD
13027 case 'ccsid858':
13028 case 'cp858':
13029 case 'ibm858':
13030 case 'pcmultilingual850euro':
13031 return 'IBM00858';
f954bd49 13032
a6e043ff
AD
13033 case '860':
13034 case 'cp860':
13035 case 'csibm860':
13036 case 'ibm860':
13037 return 'IBM860';
f954bd49 13038
a6e043ff
AD
13039 case '861':
13040 case 'cp861':
13041 case 'cpis':
13042 case 'csibm861':
13043 case 'ibm861':
13044 return 'IBM861';
f954bd49 13045
a6e043ff
AD
13046 case '862':
13047 case 'cp862':
13048 case 'cspc862latinhebrew':
13049 case 'ibm862':
13050 return 'IBM862';
f954bd49 13051
a6e043ff
AD
13052 case '863':
13053 case 'cp863':
13054 case 'csibm863':
13055 case 'ibm863':
13056 return 'IBM863';
f954bd49 13057
a6e043ff
AD
13058 case 'cp864':
13059 case 'csibm864':
13060 case 'ibm864':
13061 return 'IBM864';
f954bd49 13062
a6e043ff
AD
13063 case '865':
13064 case 'cp865':
13065 case 'csibm865':
13066 case 'ibm865':
13067 return 'IBM865';
f954bd49 13068
a6e043ff
AD
13069 case '866':
13070 case 'cp866':
13071 case 'csibm866':
13072 case 'ibm866':
13073 return 'IBM866';
f954bd49 13074
a6e043ff
AD
13075 case 'cp868':
13076 case 'cpar':
13077 case 'csibm868':
13078 case 'ibm868':
13079 return 'IBM868';
f954bd49 13080
a6e043ff
AD
13081 case '869':
13082 case 'cp869':
13083 case 'cpgr':
13084 case 'csibm869':
13085 case 'ibm869':
13086 return 'IBM869';
f954bd49 13087
a6e043ff
AD
13088 case 'cp870':
13089 case 'csibm870':
13090 case 'ebcdiccproece':
13091 case 'ebcdiccpyu':
13092 case 'ibm870':
13093 return 'IBM870';
f954bd49 13094
a6e043ff
AD
13095 case 'cp871':
13096 case 'csibm871':
13097 case 'ebcdiccpis':
13098 case 'ibm871':
13099 return 'IBM871';
f954bd49 13100
a6e043ff
AD
13101 case 'cp880':
13102 case 'csibm880':
13103 case 'ebcdiccyrillic':
13104 case 'ibm880':
13105 return 'IBM880';
f954bd49 13106
a6e043ff
AD
13107 case 'cp891':
13108 case 'csibm891':
13109 case 'ibm891':
13110 return 'IBM891';
f954bd49 13111
a6e043ff
AD
13112 case 'cp903':
13113 case 'csibm903':
13114 case 'ibm903':
13115 return 'IBM903';
f954bd49 13116
a6e043ff
AD
13117 case '904':
13118 case 'cp904':
13119 case 'csibbm904':
13120 case 'ibm904':
13121 return 'IBM904';
f954bd49 13122
a6e043ff
AD
13123 case 'cp905':
13124 case 'csibm905':
13125 case 'ebcdiccptr':
13126 case 'ibm905':
13127 return 'IBM905';
f954bd49 13128
a6e043ff
AD
13129 case 'cp918':
13130 case 'csibm918':
13131 case 'ebcdiccpar2':
13132 case 'ibm918':
13133 return 'IBM918';
f954bd49 13134
a6e043ff
AD
13135 case 'ccsid924':
13136 case 'cp924':
13137 case 'ebcdiclatin9euro':
13138 case 'ibm924':
13139 return 'IBM00924';
f954bd49 13140
a6e043ff
AD
13141 case 'cp1026':
13142 case 'csibm1026':
13143 case 'ibm1026':
13144 return 'IBM1026';
f954bd49 13145
a6e043ff
AD
13146 case 'ibm1047':
13147 return 'IBM1047';
f954bd49 13148
a6e043ff
AD
13149 case 'ccsid1140':
13150 case 'cp1140':
13151 case 'ebcdicus37euro':
13152 case 'ibm1140':
13153 return 'IBM01140';
f954bd49 13154
a6e043ff
AD
13155 case 'ccsid1141':
13156 case 'cp1141':
13157 case 'ebcdicde273euro':
13158 case 'ibm1141':
13159 return 'IBM01141';
f954bd49 13160
a6e043ff
AD
13161 case 'ccsid1142':
13162 case 'cp1142':
13163 case 'ebcdicdk277euro':
13164 case 'ebcdicno277euro':
13165 case 'ibm1142':
13166 return 'IBM01142';
f954bd49 13167
a6e043ff
AD
13168 case 'ccsid1143':
13169 case 'cp1143':
13170 case 'ebcdicfi278euro':
13171 case 'ebcdicse278euro':
13172 case 'ibm1143':
13173 return 'IBM01143';
f954bd49 13174
a6e043ff
AD
13175 case 'ccsid1144':
13176 case 'cp1144':
13177 case 'ebcdicit280euro':
13178 case 'ibm1144':
13179 return 'IBM01144';
f954bd49 13180
a6e043ff
AD
13181 case 'ccsid1145':
13182 case 'cp1145':
13183 case 'ebcdices284euro':
13184 case 'ibm1145':
13185 return 'IBM01145';
f954bd49 13186
a6e043ff
AD
13187 case 'ccsid1146':
13188 case 'cp1146':
13189 case 'ebcdicgb285euro':
13190 case 'ibm1146':
13191 return 'IBM01146';
f954bd49 13192
a6e043ff
AD
13193 case 'ccsid1147':
13194 case 'cp1147':
13195 case 'ebcdicfr297euro':
13196 case 'ibm1147':
13197 return 'IBM01147';
f954bd49 13198
a6e043ff
AD
13199 case 'ccsid1148':
13200 case 'cp1148':
13201 case 'ebcdicinternational500euro':
13202 case 'ibm1148':
13203 return 'IBM01148';
f954bd49 13204
a6e043ff
AD
13205 case 'ccsid1149':
13206 case 'cp1149':
13207 case 'ebcdicis871euro':
13208 case 'ibm1149':
13209 return 'IBM01149';
f954bd49 13210
a6e043ff
AD
13211 case 'csiso143iecp271':
13212 case 'iecp271':
13213 case 'isoir143':
13214 return 'IEC_P27-1';
f954bd49 13215
a6e043ff
AD
13216 case 'csiso49inis':
13217 case 'inis':
13218 case 'isoir49':
13219 return 'INIS';
f954bd49 13220
a6e043ff
AD
13221 case 'csiso50inis8':
13222 case 'inis8':
13223 case 'isoir50':
13224 return 'INIS-8';
f954bd49 13225
a6e043ff
AD
13226 case 'csiso51iniscyrillic':
13227 case 'iniscyrillic':
13228 case 'isoir51':
13229 return 'INIS-cyrillic';
f954bd49 13230
a6e043ff
AD
13231 case 'csinvariant':
13232 case 'invariant':
13233 return 'INVARIANT';
f954bd49 13234
a6e043ff
AD
13235 case 'iso2022cn':
13236 return 'ISO-2022-CN';
f954bd49 13237
a6e043ff
AD
13238 case 'iso2022cnext':
13239 return 'ISO-2022-CN-EXT';
f954bd49 13240
a6e043ff
AD
13241 case 'csiso2022jp':
13242 case 'iso2022jp':
13243 return 'ISO-2022-JP';
f954bd49 13244
a6e043ff
AD
13245 case 'csiso2022jp2':
13246 case 'iso2022jp2':
13247 return 'ISO-2022-JP-2';
f954bd49 13248
a6e043ff
AD
13249 case 'csiso2022kr':
13250 case 'iso2022kr':
13251 return 'ISO-2022-KR';
f954bd49 13252
a6e043ff
AD
13253 case 'cswindows30latin1':
13254 case 'iso88591windows30latin1':
13255 return 'ISO-8859-1-Windows-3.0-Latin-1';
f954bd49 13256
a6e043ff
AD
13257 case 'cswindows31latin1':
13258 case 'iso88591windows31latin1':
13259 return 'ISO-8859-1-Windows-3.1-Latin-1';
f954bd49 13260
a6e043ff
AD
13261 case 'csisolatin2':
13262 case 'iso88592':
13263 case 'iso885921987':
13264 case 'isoir101':
13265 case 'l2':
13266 case 'latin2':
13267 return 'ISO-8859-2';
f954bd49 13268
a6e043ff
AD
13269 case 'cswindows31latin2':
13270 case 'iso88592windowslatin2':
13271 return 'ISO-8859-2-Windows-Latin-2';
f954bd49 13272
a6e043ff
AD
13273 case 'csisolatin3':
13274 case 'iso88593':
13275 case 'iso885931988':
13276 case 'isoir109':
13277 case 'l3':
13278 case 'latin3':
13279 return 'ISO-8859-3';
f954bd49 13280
a6e043ff
AD
13281 case 'csisolatin4':
13282 case 'iso88594':
13283 case 'iso885941988':
13284 case 'isoir110':
13285 case 'l4':
13286 case 'latin4':
13287 return 'ISO-8859-4';
f954bd49 13288
a6e043ff
AD
13289 case 'csisolatincyrillic':
13290 case 'cyrillic':
13291 case 'iso88595':
13292 case 'iso885951988':
13293 case 'isoir144':
13294 return 'ISO-8859-5';
f954bd49 13295
a6e043ff
AD
13296 case 'arabic':
13297 case 'asmo708':
13298 case 'csisolatinarabic':
13299 case 'ecma114':
13300 case 'iso88596':
13301 case 'iso885961987':
13302 case 'isoir127':
13303 return 'ISO-8859-6';
f954bd49 13304
a6e043ff
AD
13305 case 'csiso88596e':
13306 case 'iso88596e':
13307 return 'ISO-8859-6-E';
f954bd49 13308
a6e043ff
AD
13309 case 'csiso88596i':
13310 case 'iso88596i':
13311 return 'ISO-8859-6-I';
f954bd49 13312
a6e043ff
AD
13313 case 'csisolatingreek':
13314 case 'ecma118':
13315 case 'elot928':
13316 case 'greek':
13317 case 'greek8':
13318 case 'iso88597':
13319 case 'iso885971987':
13320 case 'isoir126':
13321 return 'ISO-8859-7';
f954bd49 13322
a6e043ff
AD
13323 case 'csisolatinhebrew':
13324 case 'hebrew':
13325 case 'iso88598':
13326 case 'iso885981988':
13327 case 'isoir138':
13328 return 'ISO-8859-8';
f954bd49 13329
a6e043ff
AD
13330 case 'csiso88598e':
13331 case 'iso88598e':
13332 return 'ISO-8859-8-E';
f954bd49 13333
a6e043ff
AD
13334 case 'csiso88598i':
13335 case 'iso88598i':
13336 return 'ISO-8859-8-I';
f954bd49 13337
a6e043ff
AD
13338 case 'cswindows31latin5':
13339 case 'iso88599windowslatin5':
13340 return 'ISO-8859-9-Windows-Latin-5';
f954bd49 13341
a6e043ff
AD
13342 case 'csisolatin6':
13343 case 'iso885910':
13344 case 'iso8859101992':
13345 case 'isoir157':
13346 case 'l6':
13347 case 'latin6':
13348 return 'ISO-8859-10';
f954bd49 13349
a6e043ff
AD
13350 case 'iso885913':
13351 return 'ISO-8859-13';
f954bd49 13352
a6e043ff
AD
13353 case 'iso885914':
13354 case 'iso8859141998':
13355 case 'isoceltic':
13356 case 'isoir199':
13357 case 'l8':
13358 case 'latin8':
13359 return 'ISO-8859-14';
f954bd49 13360
a6e043ff
AD
13361 case 'iso885915':
13362 case 'latin9':
13363 return 'ISO-8859-15';
f954bd49 13364
a6e043ff
AD
13365 case 'iso885916':
13366 case 'iso8859162001':
13367 case 'isoir226':
13368 case 'l10':
13369 case 'latin10':
13370 return 'ISO-8859-16';
f954bd49 13371
a6e043ff
AD
13372 case 'iso10646j1':
13373 return 'ISO-10646-J-1';
f954bd49 13374
a6e043ff
AD
13375 case 'csunicode':
13376 case 'iso10646ucs2':
13377 return 'ISO-10646-UCS-2';
f954bd49 13378
a6e043ff
AD
13379 case 'csucs4':
13380 case 'iso10646ucs4':
13381 return 'ISO-10646-UCS-4';
f954bd49 13382
a6e043ff
AD
13383 case 'csunicodeascii':
13384 case 'iso10646ucsbasic':
13385 return 'ISO-10646-UCS-Basic';
f954bd49 13386
a6e043ff
AD
13387 case 'csunicodelatin1':
13388 case 'iso10646':
13389 case 'iso10646unicodelatin1':
13390 return 'ISO-10646-Unicode-Latin1';
f954bd49 13391
a6e043ff
AD
13392 case 'csiso10646utf1':
13393 case 'iso10646utf1':
13394 return 'ISO-10646-UTF-1';
f954bd49 13395
a6e043ff
AD
13396 case 'csiso115481':
13397 case 'iso115481':
13398 case 'isotr115481':
13399 return 'ISO-11548-1';
f954bd49 13400
a6e043ff
AD
13401 case 'csiso90':
13402 case 'isoir90':
13403 return 'iso-ir-90';
f954bd49 13404
a6e043ff
AD
13405 case 'csunicodeibm1261':
13406 case 'isounicodeibm1261':
13407 return 'ISO-Unicode-IBM-1261';
f954bd49 13408
a6e043ff
AD
13409 case 'csunicodeibm1264':
13410 case 'isounicodeibm1264':
13411 return 'ISO-Unicode-IBM-1264';
f954bd49 13412
a6e043ff
AD
13413 case 'csunicodeibm1265':
13414 case 'isounicodeibm1265':
13415 return 'ISO-Unicode-IBM-1265';
f954bd49 13416
a6e043ff
AD
13417 case 'csunicodeibm1268':
13418 case 'isounicodeibm1268':
13419 return 'ISO-Unicode-IBM-1268';
f954bd49 13420
a6e043ff
AD
13421 case 'csunicodeibm1276':
13422 case 'isounicodeibm1276':
13423 return 'ISO-Unicode-IBM-1276';
f954bd49 13424
a6e043ff
AD
13425 case 'csiso646basic1983':
13426 case 'iso646basic1983':
13427 case 'ref':
13428 return 'ISO_646.basic:1983';
f954bd49 13429
a6e043ff
AD
13430 case 'csiso2intlrefversion':
13431 case 'irv':
13432 case 'iso646irv1983':
13433 case 'isoir2':
13434 return 'ISO_646.irv:1983';
f954bd49 13435
a6e043ff
AD
13436 case 'csiso2033':
13437 case 'e13b':
13438 case 'iso20331983':
13439 case 'isoir98':
13440 return 'ISO_2033-1983';
f954bd49 13441
a6e043ff
AD
13442 case 'csiso5427cyrillic':
13443 case 'iso5427':
13444 case 'isoir37':
13445 return 'ISO_5427';
f954bd49 13446
a6e043ff
AD
13447 case 'iso5427cyrillic1981':
13448 case 'iso54271981':
13449 case 'isoir54':
13450 return 'ISO_5427:1981';
f954bd49 13451
a6e043ff
AD
13452 case 'csiso5428greek':
13453 case 'iso54281980':
13454 case 'isoir55':
13455 return 'ISO_5428:1980';
f954bd49 13456
a6e043ff
AD
13457 case 'csiso6937add':
13458 case 'iso6937225':
13459 case 'isoir152':
13460 return 'ISO_6937-2-25';
f954bd49 13461
a6e043ff
AD
13462 case 'csisotextcomm':
13463 case 'iso69372add':
13464 case 'isoir142':
13465 return 'ISO_6937-2-add';
f2f7b699 13466
a6e043ff
AD
13467 case 'csiso8859supp':
13468 case 'iso8859supp':
13469 case 'isoir154':
13470 case 'latin125':
13471 return 'ISO_8859-supp';
f2f7b699 13472
a6e043ff
AD
13473 case 'csiso10367box':
13474 case 'iso10367box':
13475 case 'isoir155':
13476 return 'ISO_10367-box';
f2f7b699 13477
a6e043ff
AD
13478 case 'csiso15italian':
13479 case 'iso646it':
13480 case 'isoir15':
13481 case 'it':
13482 return 'IT';
f2f7b699 13483
a6e043ff
AD
13484 case 'csiso13jisc6220jp':
13485 case 'isoir13':
13486 case 'jisc62201969':
13487 case 'jisc62201969jp':
13488 case 'katakana':
13489 case 'x2017':
13490 return 'JIS_C6220-1969-jp';
f2f7b699 13491
a6e043ff
AD
13492 case 'csiso14jisc6220ro':
13493 case 'iso646jp':
13494 case 'isoir14':
13495 case 'jisc62201969ro':
13496 case 'jp':
13497 return 'JIS_C6220-1969-ro';
f2f7b699 13498
a6e043ff
AD
13499 case 'csiso42jisc62261978':
13500 case 'isoir42':
13501 case 'jisc62261978':
13502 return 'JIS_C6226-1978';
f954bd49 13503
a6e043ff
AD
13504 case 'csiso87jisx208':
13505 case 'isoir87':
13506 case 'jisc62261983':
13507 case 'jisx2081983':
13508 case 'x208':
13509 return 'JIS_C6226-1983';
f954bd49 13510
a6e043ff
AD
13511 case 'csiso91jisc62291984a':
13512 case 'isoir91':
13513 case 'jisc62291984a':
13514 case 'jpocra':
13515 return 'JIS_C6229-1984-a';
f954bd49 13516
a6e043ff
AD
13517 case 'csiso92jisc62991984b':
13518 case 'iso646jpocrb':
13519 case 'isoir92':
13520 case 'jisc62291984b':
13521 case 'jpocrb':
13522 return 'JIS_C6229-1984-b';
f954bd49 13523
a6e043ff
AD
13524 case 'csiso93jis62291984badd':
13525 case 'isoir93':
13526 case 'jisc62291984badd':
13527 case 'jpocrbadd':
13528 return 'JIS_C6229-1984-b-add';
f2f7b699 13529
a6e043ff
AD
13530 case 'csiso94jis62291984hand':
13531 case 'isoir94':
13532 case 'jisc62291984hand':
13533 case 'jpocrhand':
13534 return 'JIS_C6229-1984-hand';
f2f7b699 13535
a6e043ff
AD
13536 case 'csiso95jis62291984handadd':
13537 case 'isoir95':
13538 case 'jisc62291984handadd':
13539 case 'jpocrhandadd':
13540 return 'JIS_C6229-1984-hand-add';
f2f7b699 13541
a6e043ff
AD
13542 case 'csiso96jisc62291984kana':
13543 case 'isoir96':
13544 case 'jisc62291984kana':
13545 return 'JIS_C6229-1984-kana';
f2f7b699 13546
a6e043ff
AD
13547 case 'csjisencoding':
13548 case 'jisencoding':
13549 return 'JIS_Encoding';
f2f7b699 13550
a6e043ff
AD
13551 case 'cshalfwidthkatakana':
13552 case 'jisx201':
13553 case 'x201':
13554 return 'JIS_X0201';
f2f7b699 13555
a6e043ff
AD
13556 case 'csiso159jisx2121990':
13557 case 'isoir159':
13558 case 'jisx2121990':
13559 case 'x212':
13560 return 'JIS_X0212-1990';
f2f7b699 13561
a6e043ff
AD
13562 case 'csiso141jusib1002':
13563 case 'iso646yu':
13564 case 'isoir141':
13565 case 'js':
13566 case 'jusib1002':
13567 case 'yu':
13568 return 'JUS_I.B1.002';
f2f7b699 13569
a6e043ff
AD
13570 case 'csiso147macedonian':
13571 case 'isoir147':
13572 case 'jusib1003mac':
13573 case 'macedonian':
13574 return 'JUS_I.B1.003-mac';
f2f7b699 13575
a6e043ff
AD
13576 case 'csiso146serbian':
13577 case 'isoir146':
13578 case 'jusib1003serb':
13579 case 'serbian':
13580 return 'JUS_I.B1.003-serb';
f2f7b699 13581
a6e043ff
AD
13582 case 'koi7switched':
13583 return 'KOI7-switched';
f2f7b699 13584
a6e043ff
AD
13585 case 'cskoi8r':
13586 case 'koi8r':
13587 return 'KOI8-R';
f2f7b699 13588
a6e043ff
AD
13589 case 'koi8u':
13590 return 'KOI8-U';
f2f7b699 13591
a6e043ff
AD
13592 case 'csksc5636':
13593 case 'iso646kr':
13594 case 'ksc5636':
13595 return 'KSC5636';
f2f7b699 13596
a6e043ff
AD
13597 case 'cskz1048':
13598 case 'kz1048':
13599 case 'rk1048':
13600 case 'strk10482002':
13601 return 'KZ-1048';
f2f7b699 13602
a6e043ff
AD
13603 case 'csiso19latingreek':
13604 case 'isoir19':
13605 case 'latingreek':
13606 return 'latin-greek';
f2f7b699 13607
a6e043ff
AD
13608 case 'csiso27latingreek1':
13609 case 'isoir27':
13610 case 'latingreek1':
13611 return 'Latin-greek-1';
f2f7b699 13612
a6e043ff
AD
13613 case 'csiso158lap':
13614 case 'isoir158':
13615 case 'lap':
13616 case 'latinlap':
13617 return 'latin-lap';
f2f7b699 13618
a6e043ff
AD
13619 case 'csmacintosh':
13620 case 'mac':
13621 case 'macintosh':
13622 return 'macintosh';
13623
13624 case 'csmicrosoftpublishing':
13625 case 'microsoftpublishing':
13626 return 'Microsoft-Publishing';
f2f7b699 13627
a6e043ff
AD
13628 case 'csmnem':
13629 case 'mnem':
13630 return 'MNEM';
f2f7b699 13631
a6e043ff
AD
13632 case 'csmnemonic':
13633 case 'mnemonic':
13634 return 'MNEMONIC';
f2f7b699 13635
a6e043ff
AD
13636 case 'csiso86hungarian':
13637 case 'hu':
13638 case 'iso646hu':
13639 case 'isoir86':
13640 case 'msz77953':
13641 return 'MSZ_7795.3';
f954bd49 13642
a6e043ff
AD
13643 case 'csnatsdano':
13644 case 'isoir91':
13645 case 'natsdano':
13646 return 'NATS-DANO';
6d7d21a0 13647
a6e043ff
AD
13648 case 'csnatsdanoadd':
13649 case 'isoir92':
13650 case 'natsdanoadd':
13651 return 'NATS-DANO-ADD';
6d7d21a0 13652
a6e043ff
AD
13653 case 'csnatssefi':
13654 case 'isoir81':
13655 case 'natssefi':
13656 return 'NATS-SEFI';
6d7d21a0 13657
a6e043ff
AD
13658 case 'csnatssefiadd':
13659 case 'isoir82':
13660 case 'natssefiadd':
13661 return 'NATS-SEFI-ADD';
f954bd49 13662
a6e043ff
AD
13663 case 'csiso151cuba':
13664 case 'cuba':
13665 case 'iso646cu':
13666 case 'isoir151':
13667 case 'ncnc1081':
13668 return 'NC_NC00-10:81';
a5ae3915 13669
a6e043ff
AD
13670 case 'csiso69french':
13671 case 'fr':
13672 case 'iso646fr':
13673 case 'isoir69':
13674 case 'nfz62010':
13675 return 'NF_Z_62-010';
a5ae3915 13676
a6e043ff
AD
13677 case 'csiso25french':
13678 case 'iso646fr1':
13679 case 'isoir25':
13680 case 'nfz620101973':
13681 return 'NF_Z_62-010_(1973)';
a5ae3915 13682
a6e043ff
AD
13683 case 'csiso60danishnorwegian':
13684 case 'csiso60norwegian1':
13685 case 'iso646no':
13686 case 'isoir60':
13687 case 'no':
13688 case 'ns45511':
13689 return 'NS_4551-1';
a5ae3915 13690
a6e043ff
AD
13691 case 'csiso61norwegian2':
13692 case 'iso646no2':
13693 case 'isoir61':
13694 case 'no2':
13695 case 'ns45512':
13696 return 'NS_4551-2';
a5ae3915 13697
a6e043ff
AD
13698 case 'osdebcdicdf3irv':
13699 return 'OSD_EBCDIC_DF03_IRV';
5b085627 13700
a6e043ff
AD
13701 case 'osdebcdicdf41':
13702 return 'OSD_EBCDIC_DF04_1';
5b085627 13703
a6e043ff
AD
13704 case 'osdebcdicdf415':
13705 return 'OSD_EBCDIC_DF04_15';
5b085627 13706
a6e043ff
AD
13707 case 'cspc8danishnorwegian':
13708 case 'pc8danishnorwegian':
13709 return 'PC8-Danish-Norwegian';
6d7d21a0 13710
a6e043ff
AD
13711 case 'cspc8turkish':
13712 case 'pc8turkish':
13713 return 'PC8-Turkish';
6d7d21a0 13714
a6e043ff
AD
13715 case 'csiso16portuguese':
13716 case 'iso646pt':
13717 case 'isoir16':
13718 case 'pt':
13719 return 'PT';
6d7d21a0 13720
a6e043ff
AD
13721 case 'csiso84portuguese2':
13722 case 'iso646pt2':
13723 case 'isoir84':
13724 case 'pt2':
13725 return 'PT2';
6d7d21a0 13726
a6e043ff
AD
13727 case 'cp154':
13728 case 'csptcp154':
13729 case 'cyrillicasian':
13730 case 'pt154':
13731 case 'ptcp154':
13732 return 'PTCP154';
a5ae3915 13733
a6e043ff
AD
13734 case 'scsu':
13735 return 'SCSU';
a5ae3915 13736
a6e043ff
AD
13737 case 'csiso10swedish':
13738 case 'fi':
13739 case 'iso646fi':
13740 case 'iso646se':
13741 case 'isoir10':
13742 case 'se':
13743 case 'sen850200b':
13744 return 'SEN_850200_B';
a5ae3915 13745
a6e043ff
AD
13746 case 'csiso11swedishfornames':
13747 case 'iso646se2':
13748 case 'isoir11':
13749 case 'se2':
13750 case 'sen850200c':
13751 return 'SEN_850200_C';
a5ae3915 13752
a6e043ff
AD
13753 case 'csiso102t617bit':
13754 case 'isoir102':
13755 case 't617bit':
13756 return 'T.61-7bit';
a5ae3915 13757
a6e043ff
AD
13758 case 'csiso103t618bit':
13759 case 'isoir103':
13760 case 't61':
13761 case 't618bit':
13762 return 'T.61-8bit';
a5ae3915 13763
a6e043ff
AD
13764 case 'csiso128t101g2':
13765 case 'isoir128':
13766 case 't101g2':
13767 return 'T.101-G2';
a5ae3915 13768
a6e043ff
AD
13769 case 'cstscii':
13770 case 'tscii':
13771 return 'TSCII';
a5ae3915 13772
a6e043ff
AD
13773 case 'csunicode11':
13774 case 'unicode11':
13775 return 'UNICODE-1-1';
a5ae3915 13776
a6e043ff
AD
13777 case 'csunicode11utf7':
13778 case 'unicode11utf7':
13779 return 'UNICODE-1-1-UTF-7';
a5ae3915 13780
a6e043ff
AD
13781 case 'csunknown8bit':
13782 case 'unknown8bit':
13783 return 'UNKNOWN-8BIT';
a5ae3915 13784
a6e043ff
AD
13785 case 'ansix341968':
13786 case 'ansix341986':
13787 case 'ascii':
13788 case 'cp367':
13789 case 'csascii':
13790 case 'ibm367':
13791 case 'iso646irv1991':
13792 case 'iso646us':
13793 case 'isoir6':
13794 case 'us':
13795 case 'usascii':
13796 return 'US-ASCII';
a5ae3915 13797
a6e043ff
AD
13798 case 'csusdk':
13799 case 'usdk':
13800 return 'us-dk';
a5ae3915 13801
a6e043ff
AD
13802 case 'utf7':
13803 return 'UTF-7';
a5ae3915 13804
a6e043ff
AD
13805 case 'utf8':
13806 return 'UTF-8';
a5ae3915 13807
a6e043ff
AD
13808 case 'utf16':
13809 return 'UTF-16';
a5ae3915 13810
a6e043ff
AD
13811 case 'utf16be':
13812 return 'UTF-16BE';
a5ae3915 13813
a6e043ff
AD
13814 case 'utf16le':
13815 return 'UTF-16LE';
a5ae3915 13816
a6e043ff
AD
13817 case 'utf32':
13818 return 'UTF-32';
a5ae3915 13819
a6e043ff
AD
13820 case 'utf32be':
13821 return 'UTF-32BE';
a5ae3915 13822
a6e043ff
AD
13823 case 'utf32le':
13824 return 'UTF-32LE';
a5ae3915 13825
a6e043ff
AD
13826 case 'csventurainternational':
13827 case 'venturainternational':
13828 return 'Ventura-International';
a5ae3915 13829
a6e043ff
AD
13830 case 'csventuramath':
13831 case 'venturamath':
13832 return 'Ventura-Math';
a5ae3915 13833
a6e043ff
AD
13834 case 'csventuraus':
13835 case 'venturaus':
13836 return 'Ventura-US';
a5ae3915 13837
a6e043ff
AD
13838 case 'csiso70videotexsupp1':
13839 case 'isoir70':
13840 case 'videotexsuppl':
13841 return 'videotex-suppl';
a5ae3915 13842
a6e043ff
AD
13843 case 'csviqr':
13844 case 'viqr':
13845 return 'VIQR';
a5ae3915 13846
a6e043ff
AD
13847 case 'csviscii':
13848 case 'viscii':
13849 return 'VISCII';
a5ae3915 13850
a6e043ff
AD
13851 case 'csshiftjis':
13852 case 'cswindows31j':
13853 case 'mskanji':
13854 case 'shiftjis':
13855 case 'windows31j':
13856 return 'Windows-31J';
a5ae3915 13857
a6e043ff
AD
13858 case 'iso885911':
13859 case 'tis620':
13860 return 'windows-874';
a5ae3915 13861
a6e043ff
AD
13862 case 'cseuckr':
13863 case 'csksc56011987':
13864 case 'euckr':
13865 case 'isoir149':
13866 case 'korean':
13867 case 'ksc5601':
13868 case 'ksc56011987':
13869 case 'ksc56011989':
13870 case 'windows949':
13871 return 'windows-949';
5b085627 13872
a6e043ff
AD
13873 case 'windows1250':
13874 return 'windows-1250';
5b085627 13875
a6e043ff
AD
13876 case 'windows1251':
13877 return 'windows-1251';
5b085627 13878
a6e043ff
AD
13879 case 'cp819':
13880 case 'csisolatin1':
13881 case 'ibm819':
13882 case 'iso88591':
13883 case 'iso885911987':
13884 case 'isoir100':
13885 case 'l1':
13886 case 'latin1':
13887 case 'windows1252':
13888 return 'windows-1252';
5b085627 13889
a6e043ff
AD
13890 case 'windows1253':
13891 return 'windows-1253';
5b085627 13892
a6e043ff
AD
13893 case 'csisolatin5':
13894 case 'iso88599':
13895 case 'iso885991989':
13896 case 'isoir148':
13897 case 'l5':
13898 case 'latin5':
13899 case 'windows1254':
13900 return 'windows-1254';
5b085627 13901
a6e043ff
AD
13902 case 'windows1255':
13903 return 'windows-1255';
5b085627 13904
a6e043ff
AD
13905 case 'windows1256':
13906 return 'windows-1256';
5b085627 13907
a6e043ff
AD
13908 case 'windows1257':
13909 return 'windows-1257';
5b085627 13910
a6e043ff
AD
13911 case 'windows1258':
13912 return 'windows-1258';
5b085627 13913
a6e043ff
AD
13914 default:
13915 return $charset;
5b085627 13916 }
a6e043ff 13917 }
5b085627 13918
a6e043ff
AD
13919 public static function get_curl_version()
13920 {
13921 if (is_array($curl = curl_version()))
13922 {
13923 $curl = $curl['version'];
13924 }
13925 elseif (substr($curl, 0, 5) === 'curl/')
a5ae3915 13926 {
a6e043ff 13927 $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
a5ae3915 13928 }
a6e043ff 13929 elseif (substr($curl, 0, 8) === 'libcurl/')
a5ae3915 13930 {
a6e043ff 13931 $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
a5ae3915 13932 }
a6e043ff 13933 else
a5ae3915 13934 {
a6e043ff
AD
13935 $curl = 0;
13936 }
13937 return $curl;
13938 }
5b085627 13939
a6e043ff
AD
13940 /**
13941 * Strip HTML comments
13942 *
13943 * @param string $data Data to strip comments from
13944 * @return string Comment stripped string
13945 */
13946 public static function strip_comments($data)
13947 {
13948 $output = '';
13949 while (($start = strpos($data, '<!--')) !== false)
13950 {
13951 $output .= substr($data, 0, $start);
13952 if (($end = strpos($data, '-->', $start)) !== false)
a5ae3915 13953 {
a6e043ff 13954 $data = substr_replace($data, '', 0, $end + 3);
5b085627 13955 }
5b085627
MK
13956 else
13957 {
a6e043ff 13958 $data = '';
a5ae3915
MK
13959 }
13960 }
a6e043ff
AD
13961 return $output . $data;
13962 }
5b085627 13963
a6e043ff
AD
13964 public static function parse_date($dt)
13965 {
13966 $parser = SimplePie_Parse_Date::get();
13967 return $parser->parse($dt);
a5ae3915
MK
13968 }
13969
13970 /**
a6e043ff 13971 * Decode HTML entities
a5ae3915 13972 *
a6e043ff
AD
13973 * @deprecated Use DOMDocument instead
13974 * @param string $data Input data
13975 * @return string Output data
a5ae3915 13976 */
a6e043ff 13977 public static function entities_decode($data)
a5ae3915 13978 {
a6e043ff
AD
13979 $decoder = new SimplePie_Decode_HTML_Entities($data);
13980 return $decoder->parse();
a5ae3915
MK
13981 }
13982
13983 /**
a6e043ff 13984 * Remove RFC822 comments
a5ae3915 13985 *
a6e043ff
AD
13986 * @param string $data Data to strip comments from
13987 * @return string Comment stripped string
a5ae3915 13988 */
a6e043ff 13989 public static function uncomment_rfc822($string)
a5ae3915 13990 {
a6e043ff
AD
13991 $string = (string) $string;
13992 $position = 0;
13993 $length = strlen($string);
13994 $depth = 0;
13995
13996 $output = '';
13997
13998 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
a5ae3915 13999 {
a6e043ff
AD
14000 $output .= substr($string, $position, $pos - $position);
14001 $position = $pos + 1;
14002 if ($string[$pos - 1] !== '\\')
a5ae3915 14003 {
a6e043ff
AD
14004 $depth++;
14005 while ($depth && $position < $length)
14006 {
14007 $position += strcspn($string, '()', $position);
14008 if ($string[$position - 1] === '\\')
a5ae3915 14009 {
a6e043ff
AD
14010 $position++;
14011 continue;
a5ae3915 14012 }
a6e043ff
AD
14013 elseif (isset($string[$position]))
14014 {
14015 switch ($string[$position])
14016 {
14017 case '(':
14018 $depth++;
14019 break;
a5ae3915 14020
a6e043ff
AD
14021 case ')':
14022 $depth--;
14023 break;
14024 }
14025 $position++;
14026 }
14027 else
a5ae3915 14028 {
a6e043ff 14029 break;
a5ae3915 14030 }
a6e043ff
AD
14031 }
14032 }
14033 else
14034 {
14035 $output .= '(';
a5ae3915 14036 }
a5ae3915 14037 }
a6e043ff
AD
14038 $output .= substr($string, $position);
14039
14040 return $output;
a5ae3915
MK
14041 }
14042
a6e043ff 14043 public static function parse_mime($mime)
a5ae3915 14044 {
a6e043ff 14045 if (($pos = strpos($mime, ';')) === false)
a5ae3915 14046 {
a6e043ff 14047 return trim($mime);
a5ae3915
MK
14048 }
14049 else
14050 {
a6e043ff 14051 return trim(substr($mime, 0, $pos));
a5ae3915 14052 }
a6e043ff 14053 }
a5ae3915 14054
a6e043ff
AD
14055 public static function atom_03_construct_type($attribs)
14056 {
14057 if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
a5ae3915 14058 {
a6e043ff 14059 $mode = SIMPLEPIE_CONSTRUCT_BASE64;
a5ae3915
MK
14060 }
14061 else
14062 {
a6e043ff 14063 $mode = SIMPLEPIE_CONSTRUCT_NONE;
a5ae3915 14064 }
a6e043ff
AD
14065 if (isset($attribs['']['type']))
14066 {
14067 switch (strtolower(trim($attribs['']['type'])))
14068 {
14069 case 'text':
14070 case 'text/plain':
14071 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
a5ae3915 14072
a6e043ff
AD
14073 case 'html':
14074 case 'text/html':
14075 return SIMPLEPIE_CONSTRUCT_HTML | $mode;
a5ae3915 14076
a6e043ff
AD
14077 case 'xhtml':
14078 case 'application/xhtml+xml':
14079 return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
14080
14081 default:
14082 return SIMPLEPIE_CONSTRUCT_NONE | $mode;
14083 }
a5ae3915
MK
14084 }
14085 else
14086 {
a6e043ff 14087 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
a5ae3915 14088 }
a5ae3915
MK
14089 }
14090
a6e043ff
AD
14091 public static function atom_10_construct_type($attribs)
14092 {
14093 if (isset($attribs['']['type']))
14094 {
14095 switch (strtolower(trim($attribs['']['type'])))
14096 {
14097 case 'text':
14098 return SIMPLEPIE_CONSTRUCT_TEXT;
14099
14100 case 'html':
14101 return SIMPLEPIE_CONSTRUCT_HTML;
14102
14103 case 'xhtml':
14104 return SIMPLEPIE_CONSTRUCT_XHTML;
14105
14106 default:
14107 return SIMPLEPIE_CONSTRUCT_NONE;
14108 }
14109 }
14110 return SIMPLEPIE_CONSTRUCT_TEXT;
14111 }
14112
14113 public static function atom_10_content_construct_type($attribs)
a5ae3915 14114 {
a6e043ff 14115 if (isset($attribs['']['type']))
a5ae3915 14116 {
a6e043ff
AD
14117 $type = strtolower(trim($attribs['']['type']));
14118 switch ($type)
a5ae3915 14119 {
a6e043ff
AD
14120 case 'text':
14121 return SIMPLEPIE_CONSTRUCT_TEXT;
14122
14123 case 'html':
14124 return SIMPLEPIE_CONSTRUCT_HTML;
14125
14126 case 'xhtml':
14127 return SIMPLEPIE_CONSTRUCT_XHTML;
14128 }
14129 if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
14130 {
14131 return SIMPLEPIE_CONSTRUCT_NONE;
a5ae3915
MK
14132 }
14133 else
14134 {
a6e043ff 14135 return SIMPLEPIE_CONSTRUCT_BASE64;
a5ae3915
MK
14136 }
14137 }
14138 else
14139 {
a6e043ff 14140 return SIMPLEPIE_CONSTRUCT_TEXT;
a5ae3915
MK
14141 }
14142 }
14143
a6e043ff 14144 public static function is_isegment_nz_nc($string)
a5ae3915 14145 {
a6e043ff
AD
14146 return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
14147 }
14148
14149 public static function space_seperated_tokens($string)
14150 {
14151 $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
14152 $string_length = strlen($string);
14153
14154 $position = strspn($string, $space_characters);
14155 $tokens = array();
14156
14157 while ($position < $string_length)
a5ae3915 14158 {
a6e043ff
AD
14159 $len = strcspn($string, $space_characters, $position);
14160 $tokens[] = substr($string, $position, $len);
14161 $position += $len;
14162 $position += strspn($string, $space_characters, $position);
a5ae3915 14163 }
a6e043ff
AD
14164
14165 return $tokens;
a5ae3915
MK
14166 }
14167
14168 /**
a6e043ff 14169 * Converts a unicode codepoint to a UTF-8 character
a5ae3915 14170 *
a6e043ff
AD
14171 * @static
14172 * @param int $codepoint Unicode codepoint
14173 * @return string UTF-8 character
a5ae3915 14174 */
a6e043ff 14175 public static function codepoint_to_utf8($codepoint)
a5ae3915 14176 {
a6e043ff
AD
14177 $codepoint = (int) $codepoint;
14178 if ($codepoint < 0)
a5ae3915 14179 {
a6e043ff 14180 return false;
a5ae3915 14181 }
a6e043ff 14182 else if ($codepoint <= 0x7f)
a5ae3915 14183 {
a6e043ff 14184 return chr($codepoint);
a5ae3915 14185 }
a6e043ff 14186 else if ($codepoint <= 0x7ff)
a5ae3915 14187 {
a6e043ff 14188 return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
a5ae3915 14189 }
a6e043ff
AD
14190 else if ($codepoint <= 0xffff)
14191 {
14192 return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
14193 }
14194 else if ($codepoint <= 0x10ffff)
a5ae3915 14195 {
a6e043ff 14196 return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
a5ae3915
MK
14197 }
14198 else
14199 {
a6e043ff
AD
14200 // U+FFFD REPLACEMENT CHARACTER
14201 return "\xEF\xBF\xBD";
a5ae3915 14202 }
a5ae3915
MK
14203 }
14204
14205 /**
a6e043ff 14206 * Similar to parse_str()
a5ae3915 14207 *
a6e043ff
AD
14208 * Returns an associative array of name/value pairs, where the value is an
14209 * array of values that have used the same name
14210 *
14211 * @static
14212 * @param string $str The input string.
14213 * @return array
a5ae3915 14214 */
a6e043ff 14215 public static function parse_str($str)
a5ae3915 14216 {
a6e043ff
AD
14217 $return = array();
14218 $str = explode('&', $str);
14219
14220 foreach ($str as $section)
a5ae3915 14221 {
a6e043ff
AD
14222 if (strpos($section, '=') !== false)
14223 {
14224 list($name, $value) = explode('=', $section, 2);
14225 $return[urldecode($name)][] = urldecode($value);
14226 }
14227 else
14228 {
14229 $return[urldecode($section)][] = null;
14230 }
a5ae3915 14231 }
a6e043ff
AD
14232
14233 return $return;
a5ae3915
MK
14234 }
14235
14236 /**
a6e043ff 14237 * Detect XML encoding, as per XML 1.0 Appendix F.1
a5ae3915 14238 *
a6e043ff
AD
14239 * @todo Add support for EBCDIC
14240 * @param string $data XML data
14241 * @param SimplePie_Registry $registry Class registry
14242 * @return array Possible encodings
a5ae3915 14243 */
a6e043ff 14244 public static function xml_encoding($data, $registry)
a5ae3915 14245 {
a6e043ff
AD
14246 // UTF-32 Big Endian BOM
14247 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
a5ae3915 14248 {
a6e043ff 14249 $encoding[] = 'UTF-32BE';
a5ae3915 14250 }
a6e043ff
AD
14251 // UTF-32 Little Endian BOM
14252 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
a5ae3915 14253 {
a6e043ff 14254 $encoding[] = 'UTF-32LE';
a5ae3915 14255 }
a6e043ff
AD
14256 // UTF-16 Big Endian BOM
14257 elseif (substr($data, 0, 2) === "\xFE\xFF")
a5ae3915 14258 {
a6e043ff 14259 $encoding[] = 'UTF-16BE';
a5ae3915 14260 }
a6e043ff
AD
14261 // UTF-16 Little Endian BOM
14262 elseif (substr($data, 0, 2) === "\xFF\xFE")
a5ae3915 14263 {
a6e043ff 14264 $encoding[] = 'UTF-16LE';
a5ae3915 14265 }
a6e043ff
AD
14266 // UTF-8 BOM
14267 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
a5ae3915 14268 {
a6e043ff 14269 $encoding[] = 'UTF-8';
a5ae3915 14270 }
a6e043ff
AD
14271 // UTF-32 Big Endian Without BOM
14272 elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C")
a5ae3915 14273 {
a6e043ff
AD
14274 if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
14275 {
14276 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
14277 if ($parser->parse())
14278 {
14279 $encoding[] = $parser->encoding;
14280 }
14281 }
14282 $encoding[] = 'UTF-32BE';
a5ae3915 14283 }
a6e043ff
AD
14284 // UTF-32 Little Endian Without BOM
14285 elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00")
a5ae3915 14286 {
a6e043ff
AD
14287 if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
14288 {
14289 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
14290 if ($parser->parse())
14291 {
14292 $encoding[] = $parser->encoding;
14293 }
14294 }
14295 $encoding[] = 'UTF-32LE';
a5ae3915 14296 }
a6e043ff
AD
14297 // UTF-16 Big Endian Without BOM
14298 elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
a5ae3915 14299 {
a6e043ff
AD
14300 if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
14301 {
14302 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
14303 if ($parser->parse())
14304 {
14305 $encoding[] = $parser->encoding;
14306 }
14307 }
14308 $encoding[] = 'UTF-16BE';
a5ae3915 14309 }
a6e043ff
AD
14310 // UTF-16 Little Endian Without BOM
14311 elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
a5ae3915 14312 {
a6e043ff
AD
14313 if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
14314 {
14315 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
14316 if ($parser->parse())
14317 {
14318 $encoding[] = $parser->encoding;
14319 }
14320 }
14321 $encoding[] = 'UTF-16LE';
a5ae3915 14322 }
a6e043ff
AD
14323 // US-ASCII (or superset)
14324 elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
a5ae3915 14325 {
a6e043ff
AD
14326 if ($pos = strpos($data, "\x3F\x3E"))
14327 {
14328 $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
14329 if ($parser->parse())
14330 {
14331 $encoding[] = $parser->encoding;
14332 }
14333 }
14334 $encoding[] = 'UTF-8';
a5ae3915 14335 }
a6e043ff 14336 // Fallback to UTF-8
a5ae3915
MK
14337 else
14338 {
a6e043ff 14339 $encoding[] = 'UTF-8';
a5ae3915 14340 }
a6e043ff 14341 return $encoding;
a5ae3915
MK
14342 }
14343
a6e043ff 14344 public static function output_javascript()
a5ae3915 14345 {
a6e043ff
AD
14346 if (function_exists('ob_gzhandler'))
14347 {
14348 ob_start('ob_gzhandler');
14349 }
14350 header('Content-type: text/javascript; charset: UTF-8');
14351 header('Cache-Control: must-revalidate');
14352 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
14353 ?>
14354function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
14355 if (placeholder != '') {
14356 document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
a5ae3915 14357 }
a6e043ff
AD
14358 else {
14359 document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
a5ae3915 14360 }
a6e043ff 14361}
a5ae3915 14362
a6e043ff
AD
14363function embed_flash(bgcolor, width, height, link, loop, type) {
14364 document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
14365}
14366
14367function embed_flv(width, height, link, placeholder, loop, player) {
14368 document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>');
14369}
14370
14371function embed_wmedia(width, height, link) {
14372 document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
14373}
14374 <?php
a5ae3915
MK
14375 }
14376
14377 /**
a6e043ff 14378 * Get the SimplePie build timestamp
a5ae3915 14379 *
a6e043ff
AD
14380 * Uses the git index if it exists, otherwise uses the modification time
14381 * of the newest file.
a5ae3915 14382 */
a6e043ff 14383 public static function get_build()
a5ae3915 14384 {
a6e043ff
AD
14385 $root = dirname(dirname(__FILE__));
14386 if (file_exists($root . '/.git/index'))
14387 {
14388 return filemtime($root . '/.git/index');
14389 }
14390 elseif (file_exists($root . '/SimplePie'))
14391 {
14392 $time = 0;
14393 foreach (glob($root . '/SimplePie/*.php') as $file)
14394 {
14395 if (($mtime = filemtime($file)) > $time)
14396 {
14397 $time = $mtime;
14398 }
14399 }
14400 return $time;
14401 }
14402 elseif (file_exists(dirname(__FILE__) . '/Core.php'))
14403 {
14404 return filemtime(dirname(__FILE__) . '/Core.php');
14405 }
14406 else
14407 {
14408 return filemtime(__FILE__);
14409 }
a5ae3915
MK
14410 }
14411
14412 /**
a6e043ff 14413 * Format debugging information
6d7d21a0 14414 */
a6e043ff 14415 public static function debug(&$sp)
6d7d21a0 14416 {
a6e043ff
AD
14417 $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
14418 $info .= 'PHP ' . PHP_VERSION . "\n";
14419 if ($sp->error() !== null)
14420 {
14421 $info .= 'Error occurred: ' . $sp->error() . "\n";
14422 }
14423 else
14424 {
14425 $info .= "No error found.\n";
14426 }
14427 $info .= "Extensions:\n";
14428 $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
14429 foreach ($extensions as $ext)
14430 {
14431 if (extension_loaded($ext))
14432 {
14433 $info .= " $ext loaded\n";
14434 switch ($ext)
14435 {
14436 case 'pcre':
14437 $info .= ' Version ' . PCRE_VERSION . "\n";
14438 break;
14439 case 'curl':
14440 $version = curl_version();
14441 $info .= ' Version ' . $version['version'] . "\n";
14442 break;
14443 case 'mbstring':
14444 $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
14445 break;
14446 case 'iconv':
14447 $info .= ' Version ' . ICONV_VERSION . "\n";
14448 break;
14449 case 'xml':
14450 $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
14451 break;
14452 }
14453 }
14454 else
14455 {
14456 $info .= " $ext not loaded\n";
14457 }
14458 }
14459 return $info;
6d7d21a0
AD
14460 }
14461
a6e043ff 14462 public static function silence_errors($num, $str)
6d7d21a0 14463 {
a6e043ff 14464 // No-op
6d7d21a0 14465 }
a5ae3915 14466}
6d7d21a0 14467
a5ae3915
MK
14468/**
14469 * Class to validate and to work with IPv6 addresses.
14470 *
14471 * @package SimplePie
a6e043ff 14472 * @subpackage HTTP
a5ae3915
MK
14473 * @copyright 2003-2005 The PHP Group
14474 * @license http://www.opensource.org/licenses/bsd-license.php
14475 * @link http://pear.php.net/package/Net_IPv6
14476 * @author Alexander Merz <alexander.merz@web.de>
14477 * @author elfrink at introweb dot nl
14478 * @author Josh Peck <jmp at joshpeck dot org>
14479 * @author Geoffrey Sneddon <geoffers@gmail.com>
14480 */
14481class SimplePie_Net_IPv6
14482{
f2f7b699 14483 /**
a5ae3915 14484 * Uncompresses an IPv6 address
f2f7b699 14485 *
a6e043ff
AD
14486 * RFC 4291 allows you to compress concecutive zero pieces in an address to
14487 * '::'. This method expects a valid IPv6 address and expands the '::' to
14488 * the required number of zero pieces.
a5ae3915 14489 *
a6e043ff
AD
14490 * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
14491 * ::1 -> 0:0:0:0:0:0:0:1
a5ae3915 14492 *
a6e043ff
AD
14493 * @author Alexander Merz <alexander.merz@web.de>
14494 * @author elfrink at introweb dot nl
14495 * @author Josh Peck <jmp at joshpeck dot org>
14496 * @copyright 2003-2005 The PHP Group
14497 * @license http://www.opensource.org/licenses/bsd-license.php
14498 * @param string $ip An IPv6 address
14499 * @return string The uncompressed IPv6 address
f2f7b699 14500 */
a6e043ff 14501 public static function uncompress($ip)
f2f7b699 14502 {
a5ae3915
MK
14503 $c1 = -1;
14504 $c2 = -1;
a6e043ff 14505 if (substr_count($ip, '::') === 1)
f2f7b699 14506 {
a5ae3915
MK
14507 list($ip1, $ip2) = explode('::', $ip);
14508 if ($ip1 === '')
14509 {
14510 $c1 = -1;
14511 }
14512 else
14513 {
a6e043ff 14514 $c1 = substr_count($ip1, ':');
a5ae3915
MK
14515 }
14516 if ($ip2 === '')
14517 {
14518 $c2 = -1;
14519 }
14520 else
14521 {
a6e043ff 14522 $c2 = substr_count($ip2, ':');
a5ae3915 14523 }
a6e043ff 14524 if (strpos($ip2, '.') !== false)
a5ae3915
MK
14525 {
14526 $c2++;
14527 }
14528 // ::
14529 if ($c1 === -1 && $c2 === -1)
14530 {
a6e043ff 14531 $ip = '0:0:0:0:0:0:0:0';
a5ae3915
MK
14532 }
14533 // ::xxx
14534 else if ($c1 === -1)
14535 {
14536 $fill = str_repeat('0:', 7 - $c2);
a6e043ff 14537 $ip = str_replace('::', $fill, $ip);
a5ae3915
MK
14538 }
14539 // xxx::
14540 else if ($c2 === -1)
14541 {
14542 $fill = str_repeat(':0', 7 - $c1);
a6e043ff 14543 $ip = str_replace('::', $fill, $ip);
a5ae3915
MK
14544 }
14545 // xxx::xxx
14546 else
14547 {
a6e043ff
AD
14548 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
14549 $ip = str_replace('::', $fill, $ip);
a5ae3915 14550 }
f2f7b699 14551 }
a6e043ff 14552 return $ip;
f2f7b699
AD
14553 }
14554
6d7d21a0 14555 /**
a6e043ff 14556 * Compresses an IPv6 address
6d7d21a0 14557 *
a6e043ff
AD
14558 * RFC 4291 allows you to compress concecutive zero pieces in an address to
14559 * '::'. This method expects a valid IPv6 address and compresses consecutive
14560 * zero pieces to '::'.
a5ae3915 14561 *
a6e043ff
AD
14562 * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
14563 * 0:0:0:0:0:0:0:1 -> ::1
a5ae3915 14564 *
a6e043ff
AD
14565 * @see uncompress()
14566 * @param string $ip An IPv6 address
14567 * @return string The compressed IPv6 address
14568 */
14569 public static function compress($ip)
14570 {
14571 // Prepare the IP to be compressed
14572 $ip = self::uncompress($ip);
14573 $ip_parts = self::split_v6_v4($ip);
14574
14575 // Replace all leading zeros
14576 $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
14577
14578 // Find bunches of zeros
14579 if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
14580 {
14581 $max = 0;
14582 $pos = null;
14583 foreach ($matches[0] as $match)
14584 {
14585 if (strlen($match[0]) > $max)
14586 {
14587 $max = strlen($match[0]);
14588 $pos = $match[1];
14589 }
14590 }
14591
14592 $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
14593 }
14594
14595 if ($ip_parts[1] !== '')
14596 {
14597 return implode(':', $ip_parts);
14598 }
14599 else
14600 {
14601 return $ip_parts[0];
14602 }
14603 }
14604
14605 /**
14606 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
14607 *
14608 * RFC 4291 allows you to represent the last two parts of an IPv6 address
14609 * using the standard IPv4 representation
14610 *
14611 * Example: 0:0:0:0:0:0:13.1.68.3
14612 * 0:0:0:0:0:FFFF:129.144.52.38
14613 *
14614 * @param string $ip An IPv6 address
14615 * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
6d7d21a0 14616 */
a6e043ff 14617 private static function split_v6_v4($ip)
f2f7b699 14618 {
a6e043ff 14619 if (strpos($ip, '.') !== false)
a5ae3915
MK
14620 {
14621 $pos = strrpos($ip, ':');
a6e043ff
AD
14622 $ipv6_part = substr($ip, 0, $pos);
14623 $ipv4_part = substr($ip, $pos + 1);
14624 return array($ipv6_part, $ipv4_part);
a5ae3915
MK
14625 }
14626 else
14627 {
14628 return array($ip, '');
14629 }
6d7d21a0
AD
14630 }
14631
14632 /**
a5ae3915 14633 * Checks an IPv6 address
6d7d21a0 14634 *
a6e043ff 14635 * Checks if the given IP is a valid IPv6 address
a5ae3915 14636 *
a6e043ff
AD
14637 * @param string $ip An IPv6 address
14638 * @return bool true if $ip is a valid IPv6 address
6d7d21a0 14639 */
a6e043ff 14640 public static function check_ipv6($ip)
6d7d21a0 14641 {
a6e043ff
AD
14642 $ip = self::uncompress($ip);
14643 list($ipv6, $ipv4) = self::split_v6_v4($ip);
14644 $ipv6 = explode(':', $ipv6);
14645 $ipv4 = explode('.', $ipv4);
14646 if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
f2f7b699 14647 {
a6e043ff 14648 foreach ($ipv6 as $ipv6_part)
a5ae3915 14649 {
a6e043ff
AD
14650 // The section can't be empty
14651 if ($ipv6_part === '')
14652 return false;
14653
14654 // Nor can it be over four characters
14655 if (strlen($ipv6_part) > 4)
14656 return false;
14657
14658 // Remove leading zeros (this is safe because of the above)
14659 $ipv6_part = ltrim($ipv6_part, '0');
14660 if ($ipv6_part === '')
14661 $ipv6_part = '0';
14662
14663 // Check the value is valid
14664 $value = hexdec($ipv6_part);
14665 if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
14666 return false;
a5ae3915 14667 }
a6e043ff 14668 if (count($ipv4) === 4)
a5ae3915 14669 {
a5ae3915 14670 foreach ($ipv4 as $ipv4_part)
f2f7b699 14671 {
a6e043ff
AD
14672 $value = (int) $ipv4_part;
14673 if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
14674 return false;
f2f7b699 14675 }
a5ae3915 14676 }
a6e043ff 14677 return true;
a5ae3915
MK
14678 }
14679 else
14680 {
14681 return false;
6d7d21a0
AD
14682 }
14683 }
a6e043ff
AD
14684
14685 /**
14686 * Checks if the given IP is a valid IPv6 address
14687 *
14688 * @codeCoverageIgnore
14689 * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
14690 * @see check_ipv6
14691 * @param string $ip An IPv6 address
14692 * @return bool true if $ip is a valid IPv6 address
14693 */
14694 public static function checkIPv6($ip)
14695 {
14696 return self::check_ipv6($ip);
14697 }
6d7d21a0 14698}
f2f7b699 14699
6d7d21a0
AD
14700/**
14701 * Date Parser
14702 *
14703 * @package SimplePie
a6e043ff 14704 * @subpackage Parsing
6d7d21a0
AD
14705 */
14706class SimplePie_Parse_Date
14707{
14708 /**
14709 * Input data
14710 *
14711 * @access protected
14712 * @var string
14713 */
14714 var $date;
f2f7b699 14715
6d7d21a0
AD
14716 /**
14717 * List of days, calendar day name => ordinal day number in the week
14718 *
14719 * @access protected
14720 * @var array
14721 */
14722 var $day = array(
14723 // English
14724 'mon' => 1,
14725 'monday' => 1,
14726 'tue' => 2,
14727 'tuesday' => 2,
14728 'wed' => 3,
14729 'wednesday' => 3,
14730 'thu' => 4,
14731 'thursday' => 4,
14732 'fri' => 5,
14733 'friday' => 5,
14734 'sat' => 6,
14735 'saturday' => 6,
14736 'sun' => 7,
14737 'sunday' => 7,
14738 // Dutch
14739 'maandag' => 1,
14740 'dinsdag' => 2,
14741 'woensdag' => 3,
14742 'donderdag' => 4,
14743 'vrijdag' => 5,
14744 'zaterdag' => 6,
14745 'zondag' => 7,
14746 // French
14747 'lundi' => 1,
14748 'mardi' => 2,
14749 'mercredi' => 3,
14750 'jeudi' => 4,
14751 'vendredi' => 5,
14752 'samedi' => 6,
14753 'dimanche' => 7,
14754 // German
14755 'montag' => 1,
14756 'dienstag' => 2,
14757 'mittwoch' => 3,
14758 'donnerstag' => 4,
14759 'freitag' => 5,
14760 'samstag' => 6,
14761 'sonnabend' => 6,
14762 'sonntag' => 7,
14763 // Italian
14764 'lunedì' => 1,
14765 'martedì' => 2,
14766 'mercoledì' => 3,
14767 'giovedì' => 4,
14768 'venerdì' => 5,
14769 'sabato' => 6,
14770 'domenica' => 7,
14771 // Spanish
14772 'lunes' => 1,
14773 'martes' => 2,
14774 'miércoles' => 3,
14775 'jueves' => 4,
14776 'viernes' => 5,
14777 'sábado' => 6,
14778 'domingo' => 7,
14779 // Finnish
14780 'maanantai' => 1,
14781 'tiistai' => 2,
14782 'keskiviikko' => 3,
14783 'torstai' => 4,
14784 'perjantai' => 5,
14785 'lauantai' => 6,
14786 'sunnuntai' => 7,
14787 // Hungarian
14788 'hétfő' => 1,
14789 'kedd' => 2,
14790 'szerda' => 3,
14791 'csütörtok' => 4,
14792 'péntek' => 5,
14793 'szombat' => 6,
14794 'vasárnap' => 7,
14795 // Greek
14796 'Δευ' => 1,
14797 'Τρι' => 2,
14798 'Τετ' => 3,
14799 'Πεμ' => 4,
14800 'Παρ' => 5,
14801 'Σαβ' => 6,
14802 'Κυρ' => 7,
14803 );
f2f7b699 14804
6d7d21a0
AD
14805 /**
14806 * List of months, calendar month name => calendar month number
14807 *
14808 * @access protected
14809 * @var array
14810 */
14811 var $month = array(
14812 // English
14813 'jan' => 1,
14814 'january' => 1,
14815 'feb' => 2,
14816 'february' => 2,
14817 'mar' => 3,
14818 'march' => 3,
14819 'apr' => 4,
14820 'april' => 4,
14821 'may' => 5,
14822 // No long form of May
14823 'jun' => 6,
14824 'june' => 6,
14825 'jul' => 7,
14826 'july' => 7,
14827 'aug' => 8,
14828 'august' => 8,
14829 'sep' => 9,
14830 'september' => 8,
14831 'oct' => 10,
14832 'october' => 10,
14833 'nov' => 11,
14834 'november' => 11,
14835 'dec' => 12,
14836 'december' => 12,
14837 // Dutch
14838 'januari' => 1,
14839 'februari' => 2,
14840 'maart' => 3,
14841 'april' => 4,
14842 'mei' => 5,
14843 'juni' => 6,
14844 'juli' => 7,
14845 'augustus' => 8,
14846 'september' => 9,
14847 'oktober' => 10,
14848 'november' => 11,
14849 'december' => 12,
14850 // French
14851 'janvier' => 1,
14852 'février' => 2,
14853 'mars' => 3,
14854 'avril' => 4,
14855 'mai' => 5,
14856 'juin' => 6,
14857 'juillet' => 7,
14858 'août' => 8,
14859 'septembre' => 9,
14860 'octobre' => 10,
14861 'novembre' => 11,
14862 'décembre' => 12,
14863 // German
14864 'januar' => 1,
14865 'februar' => 2,
14866 'märz' => 3,
14867 'april' => 4,
14868 'mai' => 5,
14869 'juni' => 6,
14870 'juli' => 7,
14871 'august' => 8,
14872 'september' => 9,
14873 'oktober' => 10,
14874 'november' => 11,
14875 'dezember' => 12,
14876 // Italian
14877 'gennaio' => 1,
14878 'febbraio' => 2,
14879 'marzo' => 3,
14880 'aprile' => 4,
14881 'maggio' => 5,
14882 'giugno' => 6,
14883 'luglio' => 7,
14884 'agosto' => 8,
14885 'settembre' => 9,
14886 'ottobre' => 10,
14887 'novembre' => 11,
14888 'dicembre' => 12,
14889 // Spanish
14890 'enero' => 1,
14891 'febrero' => 2,
14892 'marzo' => 3,
14893 'abril' => 4,
14894 'mayo' => 5,
14895 'junio' => 6,
14896 'julio' => 7,
14897 'agosto' => 8,
14898 'septiembre' => 9,
14899 'setiembre' => 9,
14900 'octubre' => 10,
14901 'noviembre' => 11,
14902 'diciembre' => 12,
14903 // Finnish
14904 'tammikuu' => 1,
14905 'helmikuu' => 2,
14906 'maaliskuu' => 3,
14907 'huhtikuu' => 4,
14908 'toukokuu' => 5,
14909 'kesäkuu' => 6,
14910 'heinäkuu' => 7,
14911 'elokuu' => 8,
14912 'suuskuu' => 9,
14913 'lokakuu' => 10,
14914 'marras' => 11,
14915 'joulukuu' => 12,
14916 // Hungarian
14917 'január' => 1,
14918 'február' => 2,
14919 'március' => 3,
14920 'április' => 4,
14921 'május' => 5,
14922 'június' => 6,
14923 'július' => 7,
14924 'augusztus' => 8,
14925 'szeptember' => 9,
14926 'október' => 10,
14927 'november' => 11,
14928 'december' => 12,
14929 // Greek
14930 'Ιαν' => 1,
14931 'Φεβ' => 2,
14932 'Μάώ' => 3,
14933 'Μαώ' => 3,
14934 'Απρ' => 4,
14935 'Μάι' => 5,
14936 'Μαϊ' => 5,
14937 'Μαι' => 5,
14938 'Ιούν' => 6,
14939 'Ιον' => 6,
14940 'Ιούλ' => 7,
14941 'Ιολ' => 7,
14942 'Αύγ' => 8,
14943 'Αυγ' => 8,
14944 'Σεπ' => 9,
14945 'Οκτ' => 10,
14946 'Νοέ' => 11,
14947 'Δεκ' => 12,
14948 );
f2f7b699 14949
6d7d21a0
AD
14950 /**
14951 * List of timezones, abbreviation => offset from UTC
14952 *
14953 * @access protected
14954 * @var array
14955 */
14956 var $timezone = array(
14957 'ACDT' => 37800,
14958 'ACIT' => 28800,
14959 'ACST' => 34200,
14960 'ACT' => -18000,
14961 'ACWDT' => 35100,
14962 'ACWST' => 31500,
14963 'AEDT' => 39600,
14964 'AEST' => 36000,
14965 'AFT' => 16200,
14966 'AKDT' => -28800,
14967 'AKST' => -32400,
14968 'AMDT' => 18000,
14969 'AMT' => -14400,
14970 'ANAST' => 46800,
14971 'ANAT' => 43200,
14972 'ART' => -10800,
14973 'AZOST' => -3600,
14974 'AZST' => 18000,
14975 'AZT' => 14400,
14976 'BIOT' => 21600,
14977 'BIT' => -43200,
14978 'BOT' => -14400,
14979 'BRST' => -7200,
14980 'BRT' => -10800,
14981 'BST' => 3600,
14982 'BTT' => 21600,
14983 'CAST' => 18000,
14984 'CAT' => 7200,
14985 'CCT' => 23400,
14986 'CDT' => -18000,
14987 'CEDT' => 7200,
14988 'CET' => 3600,
14989 'CGST' => -7200,
14990 'CGT' => -10800,
14991 'CHADT' => 49500,
14992 'CHAST' => 45900,
14993 'CIST' => -28800,
14994 'CKT' => -36000,
14995 'CLDT' => -10800,
14996 'CLST' => -14400,
14997 'COT' => -18000,
14998 'CST' => -21600,
14999 'CVT' => -3600,
15000 'CXT' => 25200,
15001 'DAVT' => 25200,
15002 'DTAT' => 36000,
15003 'EADT' => -18000,
15004 'EAST' => -21600,
15005 'EAT' => 10800,
15006 'ECT' => -18000,
15007 'EDT' => -14400,
15008 'EEST' => 10800,
15009 'EET' => 7200,
15010 'EGT' => -3600,
15011 'EKST' => 21600,
15012 'EST' => -18000,
15013 'FJT' => 43200,
15014 'FKDT' => -10800,
15015 'FKST' => -14400,
15016 'FNT' => -7200,
15017 'GALT' => -21600,
15018 'GEDT' => 14400,
15019 'GEST' => 10800,
15020 'GFT' => -10800,
15021 'GILT' => 43200,
15022 'GIT' => -32400,
15023 'GST' => 14400,
15024 'GST' => -7200,
15025 'GYT' => -14400,
15026 'HAA' => -10800,
15027 'HAC' => -18000,
15028 'HADT' => -32400,
15029 'HAE' => -14400,
15030 'HAP' => -25200,
15031 'HAR' => -21600,
15032 'HAST' => -36000,
15033 'HAT' => -9000,
15034 'HAY' => -28800,
15035 'HKST' => 28800,
15036 'HMT' => 18000,
15037 'HNA' => -14400,
15038 'HNC' => -21600,
15039 'HNE' => -18000,
15040 'HNP' => -28800,
15041 'HNR' => -25200,
15042 'HNT' => -12600,
15043 'HNY' => -32400,
15044 'IRDT' => 16200,
15045 'IRKST' => 32400,
15046 'IRKT' => 28800,
15047 'IRST' => 12600,
15048 'JFDT' => -10800,
15049 'JFST' => -14400,
15050 'JST' => 32400,
15051 'KGST' => 21600,
15052 'KGT' => 18000,
15053 'KOST' => 39600,
15054 'KOVST' => 28800,
15055 'KOVT' => 25200,
15056 'KRAST' => 28800,
15057 'KRAT' => 25200,
15058 'KST' => 32400,
15059 'LHDT' => 39600,
15060 'LHST' => 37800,
15061 'LINT' => 50400,
15062 'LKT' => 21600,
15063 'MAGST' => 43200,
15064 'MAGT' => 39600,
15065 'MAWT' => 21600,
15066 'MDT' => -21600,
15067 'MESZ' => 7200,
15068 'MEZ' => 3600,
15069 'MHT' => 43200,
15070 'MIT' => -34200,
15071 'MNST' => 32400,
15072 'MSDT' => 14400,
15073 'MSST' => 10800,
15074 'MST' => -25200,
15075 'MUT' => 14400,
15076 'MVT' => 18000,
15077 'MYT' => 28800,
15078 'NCT' => 39600,
15079 'NDT' => -9000,
15080 'NFT' => 41400,
15081 'NMIT' => 36000,
15082 'NOVST' => 25200,
15083 'NOVT' => 21600,
15084 'NPT' => 20700,
15085 'NRT' => 43200,
15086 'NST' => -12600,
15087 'NUT' => -39600,
15088 'NZDT' => 46800,
15089 'NZST' => 43200,
15090 'OMSST' => 25200,
15091 'OMST' => 21600,
15092 'PDT' => -25200,
15093 'PET' => -18000,
15094 'PETST' => 46800,
15095 'PETT' => 43200,
15096 'PGT' => 36000,
15097 'PHOT' => 46800,
15098 'PHT' => 28800,
15099 'PKT' => 18000,
15100 'PMDT' => -7200,
15101 'PMST' => -10800,
15102 'PONT' => 39600,
15103 'PST' => -28800,
15104 'PWT' => 32400,
15105 'PYST' => -10800,
15106 'PYT' => -14400,
15107 'RET' => 14400,
15108 'ROTT' => -10800,
15109 'SAMST' => 18000,
15110 'SAMT' => 14400,
15111 'SAST' => 7200,
15112 'SBT' => 39600,
15113 'SCDT' => 46800,
15114 'SCST' => 43200,
15115 'SCT' => 14400,
15116 'SEST' => 3600,
15117 'SGT' => 28800,
15118 'SIT' => 28800,
15119 'SRT' => -10800,
15120 'SST' => -39600,
15121 'SYST' => 10800,
15122 'SYT' => 7200,
15123 'TFT' => 18000,
15124 'THAT' => -36000,
15125 'TJT' => 18000,
15126 'TKT' => -36000,
15127 'TMT' => 18000,
15128 'TOT' => 46800,
15129 'TPT' => 32400,
15130 'TRUT' => 36000,
15131 'TVT' => 43200,
15132 'TWT' => 28800,
15133 'UYST' => -7200,
15134 'UYT' => -10800,
15135 'UZT' => 18000,
15136 'VET' => -14400,
15137 'VLAST' => 39600,
15138 'VLAT' => 36000,
15139 'VOST' => 21600,
15140 'VUT' => 39600,
15141 'WAST' => 7200,
15142 'WAT' => 3600,
15143 'WDT' => 32400,
15144 'WEST' => 3600,
15145 'WFT' => 43200,
15146 'WIB' => 25200,
15147 'WIT' => 32400,
15148 'WITA' => 28800,
15149 'WKST' => 18000,
15150 'WST' => 28800,
15151 'YAKST' => 36000,
15152 'YAKT' => 32400,
15153 'YAPT' => 36000,
15154 'YEKST' => 21600,
15155 'YEKT' => 18000,
15156 );
f2f7b699 15157
6d7d21a0 15158 /**
a6e043ff
AD
15159 * Cached PCRE for SimplePie_Parse_Date::$day
15160 *
15161 * @access protected
15162 * @var string
15163 */
15164 var $day_pcre;
15165
15166 /**
15167 * Cached PCRE for SimplePie_Parse_Date::$month
15168 *
15169 * @access protected
15170 * @var string
15171 */
15172 var $month_pcre;
15173
15174 /**
15175 * Array of user-added callback methods
15176 *
15177 * @access private
15178 * @var array
15179 */
15180 var $built_in = array();
15181
15182 /**
15183 * Array of user-added callback methods
15184 *
15185 * @access private
15186 * @var array
15187 */
15188 var $user = array();
15189
15190 /**
15191 * Create new SimplePie_Parse_Date object, and set self::day_pcre,
15192 * self::month_pcre, and self::built_in
15193 *
15194 * @access private
15195 */
15196 public function __construct()
15197 {
15198 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
15199 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
15200
15201 static $cache;
15202 if (!isset($cache[get_class($this)]))
15203 {
15204 $all_methods = get_class_methods($this);
15205
15206 foreach ($all_methods as $method)
15207 {
15208 if (strtolower(substr($method, 0, 5)) === 'date_')
15209 {
15210 $cache[get_class($this)][] = $method;
15211 }
15212 }
15213 }
15214
15215 foreach ($cache[get_class($this)] as $method)
15216 {
15217 $this->built_in[] = $method;
15218 }
15219 }
15220
15221 /**
15222 * Get the object
15223 *
15224 * @access public
15225 */
15226 public static function get()
15227 {
15228 static $object;
15229 if (!$object)
15230 {
15231 $object = new SimplePie_Parse_Date;
15232 }
15233 return $object;
15234 }
15235
15236 /**
15237 * Parse a date
15238 *
15239 * @final
15240 * @access public
15241 * @param string $date Date to parse
15242 * @return int Timestamp corresponding to date string, or false on failure
15243 */
15244 public function parse($date)
15245 {
15246 foreach ($this->user as $method)
15247 {
15248 if (($returned = call_user_func($method, $date)) !== false)
15249 {
15250 return $returned;
15251 }
15252 }
15253
15254 foreach ($this->built_in as $method)
15255 {
15256 if (($returned = call_user_func(array($this, $method), $date)) !== false)
15257 {
15258 return $returned;
15259 }
15260 }
15261
15262 return false;
15263 }
15264
15265 /**
15266 * Add a callback method to parse a date
6d7d21a0 15267 *
a6e043ff
AD
15268 * @final
15269 * @access public
15270 * @param callback $callback
6d7d21a0 15271 */
a6e043ff
AD
15272 public function add_callback($callback)
15273 {
15274 if (is_callable($callback))
15275 {
15276 $this->user[] = $callback;
15277 }
15278 else
15279 {
15280 trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
15281 }
15282 }
f2f7b699 15283
6d7d21a0 15284 /**
a6e043ff
AD
15285 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
15286 * well as allowing any of upper or lower case "T", horizontal tabs, or
15287 * spaces to be used as the time seperator (including more than one))
6d7d21a0
AD
15288 *
15289 * @access protected
a6e043ff 15290 * @return int Timestamp
6d7d21a0 15291 */
a6e043ff
AD
15292 public function date_w3cdtf($date)
15293 {
15294 static $pcre;
15295 if (!$pcre)
15296 {
15297 $year = '([0-9]{4})';
15298 $month = $day = $hour = $minute = $second = '([0-9]{2})';
15299 $decimal = '([0-9]*)';
15300 $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
15301 $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
15302 }
15303 if (preg_match($pcre, $date, $match))
15304 {
15305 /*
15306 Capturing subpatterns:
15307 1: Year
15308 2: Month
15309 3: Day
15310 4: Hour
15311 5: Minute
15312 6: Second
15313 7: Decimal fraction of a second
15314 8: Zulu
15315 9: Timezone ±
15316 10: Timezone hours
15317 11: Timezone minutes
15318 */
f2f7b699 15319
a6e043ff
AD
15320 // Fill in empty matches
15321 for ($i = count($match); $i <= 3; $i++)
15322 {
15323 $match[$i] = '1';
15324 }
15325
15326 for ($i = count($match); $i <= 7; $i++)
15327 {
15328 $match[$i] = '0';
15329 }
15330
15331 // Numeric timezone
15332 if (isset($match[9]) && $match[9] !== '')
15333 {
15334 $timezone = $match[10] * 3600;
15335 $timezone += $match[11] * 60;
15336 if ($match[9] === '-')
15337 {
15338 $timezone = 0 - $timezone;
15339 }
15340 }
15341 else
15342 {
15343 $timezone = 0;
15344 }
15345
15346 // Convert the number of seconds to an integer, taking decimals into account
15347 $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
15348
15349 return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
15350 }
15351 else
15352 {
15353 return false;
15354 }
15355 }
f2f7b699 15356
6d7d21a0 15357 /**
a6e043ff 15358 * Remove RFC822 comments
6d7d21a0 15359 *
a6e043ff
AD
15360 * @access protected
15361 * @param string $data Data to strip comments from
15362 * @return string Comment stripped string
6d7d21a0 15363 */
a6e043ff
AD
15364 public function remove_rfc2822_comments($string)
15365 {
15366 $string = (string) $string;
15367 $position = 0;
15368 $length = strlen($string);
15369 $depth = 0;
15370
15371 $output = '';
15372
15373 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
15374 {
15375 $output .= substr($string, $position, $pos - $position);
15376 $position = $pos + 1;
15377 if ($string[$pos - 1] !== '\\')
15378 {
15379 $depth++;
15380 while ($depth && $position < $length)
15381 {
15382 $position += strcspn($string, '()', $position);
15383 if ($string[$position - 1] === '\\')
15384 {
15385 $position++;
15386 continue;
15387 }
15388 elseif (isset($string[$position]))
15389 {
15390 switch ($string[$position])
15391 {
15392 case '(':
15393 $depth++;
15394 break;
15395
15396 case ')':
15397 $depth--;
15398 break;
15399 }
15400 $position++;
15401 }
15402 else
15403 {
15404 break;
15405 }
15406 }
15407 }
15408 else
15409 {
15410 $output .= '(';
15411 }
15412 }
15413 $output .= substr($string, $position);
15414
15415 return $output;
15416 }
f2f7b699 15417
6d7d21a0 15418 /**
a6e043ff 15419 * Parse RFC2822's date format
6d7d21a0 15420 *
a6e043ff
AD
15421 * @access protected
15422 * @return int Timestamp
6d7d21a0 15423 */
a6e043ff 15424 public function date_rfc2822($date)
6d7d21a0 15425 {
a6e043ff
AD
15426 static $pcre;
15427 if (!$pcre)
6d7d21a0 15428 {
a6e043ff
AD
15429 $wsp = '[\x09\x20]';
15430 $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
15431 $optional_fws = $fws . '?';
15432 $day_name = $this->day_pcre;
15433 $month = $this->month_pcre;
15434 $day = '([0-9]{1,2})';
15435 $hour = $minute = $second = '([0-9]{2})';
15436 $year = '([0-9]{2,4})';
15437 $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
15438 $character_zone = '([A-Z]{1,5})';
15439 $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
15440 $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
15441 }
15442 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
15443 {
15444 /*
15445 Capturing subpatterns:
15446 1: Day name
15447 2: Day
15448 3: Month
15449 4: Year
15450 5: Hour
15451 6: Minute
15452 7: Second
15453 8: Timezone ±
15454 9: Timezone hours
15455 10: Timezone minutes
15456 11: Alphabetic timezone
15457 */
f954bd49 15458
a6e043ff
AD
15459 // Find the month number
15460 $month = $this->month[strtolower($match[3])];
15461
15462 // Numeric timezone
15463 if ($match[8] !== '')
f2f7b699 15464 {
a6e043ff
AD
15465 $timezone = $match[9] * 3600;
15466 $timezone += $match[10] * 60;
15467 if ($match[8] === '-')
6d7d21a0 15468 {
a6e043ff 15469 $timezone = 0 - $timezone;
6d7d21a0 15470 }
f2f7b699 15471 }
a6e043ff
AD
15472 // Character timezone
15473 elseif (isset($this->timezone[strtoupper($match[11])]))
15474 {
15475 $timezone = $this->timezone[strtoupper($match[11])];
15476 }
15477 // Assume everything else to be -0000
15478 else
15479 {
15480 $timezone = 0;
15481 }
15482
15483 // Deal with 2/3 digit years
15484 if ($match[4] < 50)
15485 {
15486 $match[4] += 2000;
15487 }
15488 elseif ($match[4] < 1000)
15489 {
15490 $match[4] += 1900;
15491 }
15492
15493 // Second is optional, if it is empty set it to zero
15494 if ($match[7] !== '')
15495 {
15496 $second = $match[7];
15497 }
15498 else
15499 {
15500 $second = 0;
15501 }
15502
15503 return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
f2f7b699 15504 }
a6e043ff 15505 else
6d7d21a0 15506 {
a6e043ff 15507 return false;
6d7d21a0 15508 }
f2f7b699 15509 }
f954bd49 15510
f2f7b699 15511 /**
a6e043ff 15512 * Parse RFC850's date format
f2f7b699 15513 *
a6e043ff
AD
15514 * @access protected
15515 * @return int Timestamp
f2f7b699 15516 */
a6e043ff 15517 public function date_rfc850($date)
f2f7b699 15518 {
a6e043ff
AD
15519 static $pcre;
15520 if (!$pcre)
6d7d21a0 15521 {
a6e043ff
AD
15522 $space = '[\x09\x20]+';
15523 $day_name = $this->day_pcre;
15524 $month = $this->month_pcre;
15525 $day = '([0-9]{1,2})';
15526 $year = $hour = $minute = $second = '([0-9]{2})';
15527 $zone = '([A-Z]{1,5})';
15528 $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
6d7d21a0 15529 }
a6e043ff 15530 if (preg_match($pcre, $date, $match))
f2f7b699 15531 {
a6e043ff
AD
15532 /*
15533 Capturing subpatterns:
15534 1: Day name
15535 2: Day
15536 3: Month
15537 4: Year
15538 5: Hour
15539 6: Minute
15540 7: Second
15541 8: Timezone
15542 */
15543
15544 // Month
15545 $month = $this->month[strtolower($match[3])];
15546
15547 // Character timezone
15548 if (isset($this->timezone[strtoupper($match[8])]))
6d7d21a0 15549 {
a6e043ff 15550 $timezone = $this->timezone[strtoupper($match[8])];
6d7d21a0 15551 }
a6e043ff
AD
15552 // Assume everything else to be -0000
15553 else
6d7d21a0 15554 {
a6e043ff 15555 $timezone = 0;
6d7d21a0 15556 }
6d7d21a0 15557
a6e043ff
AD
15558 // Deal with 2 digit year
15559 if ($match[4] < 50)
15560 {
15561 $match[4] += 2000;
15562 }
15563 else
15564 {
15565 $match[4] += 1900;
15566 }
f2f7b699 15567
a6e043ff 15568 return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
f2f7b699
AD
15569 }
15570 else
15571 {
a6e043ff 15572 return false;
f2f7b699
AD
15573 }
15574 }
15575
6d7d21a0 15576 /**
a6e043ff 15577 * Parse C99's asctime()'s date format
6d7d21a0
AD
15578 *
15579 * @access protected
15580 * @return int Timestamp
15581 */
a6e043ff 15582 public function date_asctime($date)
f2f7b699 15583 {
6d7d21a0
AD
15584 static $pcre;
15585 if (!$pcre)
f2f7b699 15586 {
a6e043ff
AD
15587 $space = '[\x09\x20]+';
15588 $wday_name = $this->day_pcre;
15589 $mon_name = $this->month_pcre;
15590 $day = '([0-9]{1,2})';
15591 $hour = $sec = $min = '([0-9]{2})';
6d7d21a0 15592 $year = '([0-9]{4})';
a6e043ff
AD
15593 $terminator = '\x0A?\x00?';
15594 $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
6d7d21a0
AD
15595 }
15596 if (preg_match($pcre, $date, $match))
15597 {
15598 /*
15599 Capturing subpatterns:
a6e043ff 15600 1: Day name
6d7d21a0
AD
15601 2: Month
15602 3: Day
15603 4: Hour
15604 5: Minute
15605 6: Second
a6e043ff 15606 7: Year
6d7d21a0
AD
15607 */
15608
a6e043ff
AD
15609 $month = $this->month[strtolower($match[2])];
15610 return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
15611 }
15612 else
15613 {
15614 return false;
15615 }
15616 }
6d7d21a0 15617
a6e043ff
AD
15618 /**
15619 * Parse dates using strtotime()
15620 *
15621 * @access protected
15622 * @return int Timestamp
15623 */
15624 public function date_strtotime($date)
15625 {
15626 $strtotime = strtotime($date);
15627 if ($strtotime === -1 || $strtotime === false)
15628 {
15629 return false;
15630 }
15631 else
15632 {
15633 return $strtotime;
15634 }
15635 }
15636}
6d7d21a0 15637
a6e043ff
AD
15638/**
15639 * Parses XML into something sane
15640 *
15641 *
15642 * This class can be overloaded with {@see SimplePie::set_parser_class()}
15643 *
15644 * @package SimplePie
15645 * @subpackage Parsing
15646 */
15647class SimplePie_Parser
15648{
15649 var $error_code;
15650 var $error_string;
15651 var $current_line;
15652 var $current_column;
15653 var $current_byte;
15654 var $separator = ' ';
15655 var $namespace = array('');
15656 var $element = array('');
15657 var $xml_base = array('');
15658 var $xml_base_explicit = array(false);
15659 var $xml_lang = array('');
15660 var $data = array();
15661 var $datas = array(array());
15662 var $current_xhtml_construct = -1;
15663 var $encoding;
15664 protected $registry;
15665
15666 public function set_registry(SimplePie_Registry $registry)
15667 {
15668 $this->registry = $registry;
15669 }
15670
15671 public function parse(&$data, $encoding)
15672 {
15673 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
15674 if (strtoupper($encoding) === 'US-ASCII')
15675 {
15676 $this->encoding = 'UTF-8';
15677 }
15678 else
15679 {
15680 $this->encoding = $encoding;
15681 }
15682
15683 // Strip BOM:
15684 // UTF-32 Big Endian BOM
15685 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
15686 {
15687 $data = substr($data, 4);
15688 }
15689 // UTF-32 Little Endian BOM
15690 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
15691 {
15692 $data = substr($data, 4);
15693 }
15694 // UTF-16 Big Endian BOM
15695 elseif (substr($data, 0, 2) === "\xFE\xFF")
15696 {
15697 $data = substr($data, 2);
15698 }
15699 // UTF-16 Little Endian BOM
15700 elseif (substr($data, 0, 2) === "\xFF\xFE")
15701 {
15702 $data = substr($data, 2);
15703 }
15704 // UTF-8 BOM
15705 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
15706 {
15707 $data = substr($data, 3);
15708 }
15709
15710 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
15711 {
15712 $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
15713 if ($declaration->parse())
6d7d21a0 15714 {
a6e043ff
AD
15715 $data = substr($data, $pos + 2);
15716 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
6d7d21a0
AD
15717 }
15718 else
15719 {
a6e043ff
AD
15720 $this->error_string = 'SimplePie bug! Please report this!';
15721 return false;
15722 }
15723 }
15724
15725 $return = true;
15726
15727 static $xml_is_sane = null;
15728 if ($xml_is_sane === null)
15729 {
15730 $parser_check = xml_parser_create();
15731 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
15732 xml_parser_free($parser_check);
15733 $xml_is_sane = isset($values[0]['value']);
15734 }
15735
15736 // Create the parser
15737 if ($xml_is_sane)
15738 {
15739 $xml = xml_parser_create_ns($this->encoding, $this->separator);
15740 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
15741 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
15742 xml_set_object($xml, $this);
15743 xml_set_character_data_handler($xml, 'cdata');
15744 xml_set_element_handler($xml, 'tag_open', 'tag_close');
15745
15746 // Parse!
15747 if (!xml_parse($xml, $data, true))
15748 {
15749 $this->error_code = xml_get_error_code($xml);
15750 $this->error_string = xml_error_string($this->error_code);
15751 $return = false;
6d7d21a0 15752 }
a6e043ff
AD
15753 $this->current_line = xml_get_current_line_number($xml);
15754 $this->current_column = xml_get_current_column_number($xml);
15755 $this->current_byte = xml_get_current_byte_index($xml);
15756 xml_parser_free($xml);
15757 return $return;
f2f7b699
AD
15758 }
15759 else
15760 {
a6e043ff
AD
15761 libxml_clear_errors();
15762 $xml = new XMLReader();
15763 $xml->xml($data);
15764 while (@$xml->read())
6d7d21a0 15765 {
a6e043ff 15766 switch ($xml->nodeType)
6d7d21a0 15767 {
6d7d21a0 15768
a6e043ff
AD
15769 case constant('XMLReader::END_ELEMENT'):
15770 if ($xml->namespaceURI !== '')
15771 {
15772 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
6d7d21a0 15773 }
a6e043ff
AD
15774 else
15775 {
15776 $tagName = $xml->localName;
15777 }
15778 $this->tag_close(null, $tagName);
15779 break;
15780 case constant('XMLReader::ELEMENT'):
15781 $empty = $xml->isEmptyElement;
15782 if ($xml->namespaceURI !== '')
15783 {
15784 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
15785 }
15786 else
15787 {
15788 $tagName = $xml->localName;
15789 }
15790 $attributes = array();
15791 while ($xml->moveToNextAttribute())
15792 {
15793 if ($xml->namespaceURI !== '')
15794 {
15795 $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
15796 }
15797 else
15798 {
15799 $attrName = $xml->localName;
15800 }
15801 $attributes[$attrName] = $xml->value;
15802 }
15803 $this->tag_open(null, $tagName, $attributes);
15804 if ($empty)
15805 {
15806 $this->tag_close(null, $tagName);
15807 }
15808 break;
15809 case constant('XMLReader::TEXT'):
15810
15811 case constant('XMLReader::CDATA'):
15812 $this->cdata(null, $xml->value);
6d7d21a0 15813 break;
6d7d21a0
AD
15814 }
15815 }
a6e043ff
AD
15816 if ($error = libxml_get_last_error())
15817 {
15818 $this->error_code = $error->code;
15819 $this->error_string = $error->message;
15820 $this->current_line = $error->line;
15821 $this->current_column = $error->column;
15822 return false;
15823 }
6d7d21a0
AD
15824 else
15825 {
a6e043ff 15826 return true;
6d7d21a0 15827 }
f2f7b699 15828 }
a6e043ff 15829 }
6d7d21a0 15830
a6e043ff
AD
15831 public function get_error_code()
15832 {
15833 return $this->error_code;
6d7d21a0
AD
15834 }
15835
a6e043ff 15836 public function get_error_string()
6d7d21a0 15837 {
a6e043ff
AD
15838 return $this->error_string;
15839 }
15840
15841 public function get_current_line()
15842 {
15843 return $this->current_line;
15844 }
15845
15846 public function get_current_column()
15847 {
15848 return $this->current_column;
15849 }
15850
15851 public function get_current_byte()
15852 {
15853 return $this->current_byte;
15854 }
15855
15856 public function get_data()
15857 {
15858 return $this->data;
15859 }
15860
15861 public function tag_open($parser, $tag, $attributes)
15862 {
15863 list($this->namespace[], $this->element[]) = $this->split_ns($tag);
15864
15865 $attribs = array();
15866 foreach ($attributes as $name => $value)
f2f7b699 15867 {
a6e043ff
AD
15868 list($attrib_namespace, $attribute) = $this->split_ns($name);
15869 $attribs[$attrib_namespace][$attribute] = $value;
f2f7b699 15870 }
f2f7b699 15871
a6e043ff
AD
15872 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
15873 {
15874 $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
15875 if ($base !== false)
6d7d21a0 15876 {
a6e043ff
AD
15877 $this->xml_base[] = $base;
15878 $this->xml_base_explicit[] = true;
6d7d21a0 15879 }
a6e043ff
AD
15880 }
15881 else
15882 {
15883 $this->xml_base[] = end($this->xml_base);
15884 $this->xml_base_explicit[] = end($this->xml_base_explicit);
15885 }
f2f7b699 15886
a6e043ff
AD
15887 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
15888 {
15889 $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
15890 }
15891 else
15892 {
15893 $this->xml_lang[] = end($this->xml_lang);
15894 }
f954bd49 15895
a6e043ff
AD
15896 if ($this->current_xhtml_construct >= 0)
15897 {
15898 $this->current_xhtml_construct++;
15899 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
6d7d21a0 15900 {
a6e043ff
AD
15901 $this->data['data'] .= '<' . end($this->element);
15902 if (isset($attribs['']))
15903 {
15904 foreach ($attribs[''] as $name => $value)
15905 {
15906 $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
15907 }
15908 }
15909 $this->data['data'] .= '>';
6d7d21a0 15910 }
a6e043ff
AD
15911 }
15912 else
15913 {
15914 $this->datas[] =& $this->data;
15915 $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
15916 $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
15917 if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml')
15918 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml')
15919 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
15920 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
15921 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
6d7d21a0 15922 {
a6e043ff 15923 $this->current_xhtml_construct = 0;
f2f7b699 15924 }
a6e043ff
AD
15925 }
15926 }
6d7d21a0 15927
a6e043ff
AD
15928 public function cdata($parser, $cdata)
15929 {
15930 if ($this->current_xhtml_construct >= 0)
15931 {
15932 $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
f2f7b699
AD
15933 }
15934 else
15935 {
a6e043ff 15936 $this->data['data'] .= $cdata;
f2f7b699
AD
15937 }
15938 }
15939
a6e043ff 15940 public function tag_close($parser, $tag)
f2f7b699 15941 {
a6e043ff 15942 if ($this->current_xhtml_construct >= 0)
f2f7b699 15943 {
a6e043ff
AD
15944 $this->current_xhtml_construct--;
15945 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
15946 {
15947 $this->data['data'] .= '</' . end($this->element) . '>';
15948 }
f2f7b699 15949 }
a6e043ff 15950 if ($this->current_xhtml_construct === -1)
f2f7b699 15951 {
a6e043ff
AD
15952 $this->data =& $this->datas[count($this->datas) - 1];
15953 array_pop($this->datas);
15954 }
f2f7b699 15955
a6e043ff
AD
15956 array_pop($this->element);
15957 array_pop($this->namespace);
15958 array_pop($this->xml_base);
15959 array_pop($this->xml_base_explicit);
15960 array_pop($this->xml_lang);
15961 }
f2f7b699 15962
a6e043ff
AD
15963 public function split_ns($string)
15964 {
15965 static $cache = array();
15966 if (!isset($cache[$string]))
15967 {
15968 if ($pos = strpos($string, $this->separator))
f2f7b699 15969 {
a6e043ff
AD
15970 static $separator_length;
15971 if (!$separator_length)
15972 {
15973 $separator_length = strlen($this->separator);
15974 }
15975 $namespace = substr($string, 0, $pos);
15976 $local_name = substr($string, $pos + $separator_length);
15977 if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
15978 {
15979 $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
15980 }
6d7d21a0 15981
a6e043ff
AD
15982 // Normalize the Media RSS namespaces
15983 if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
15984 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
15985 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
15986 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
15987 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
15988 {
15989 $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
15990 }
15991 $cache[$string] = array($namespace, $local_name);
f2f7b699
AD
15992 }
15993 else
15994 {
a6e043ff 15995 $cache[$string] = array('', $string);
f2f7b699 15996 }
f2f7b699 15997 }
a6e043ff 15998 return $cache[$string];
f2f7b699 15999 }
a6e043ff 16000}
f2f7b699 16001
a6e043ff
AD
16002/**
16003 * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
16004 *
16005 * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
16006 *
16007 * This class can be overloaded with {@see SimplePie::set_rating_class()}
16008 *
16009 * @package SimplePie
16010 * @subpackage API
16011 */
16012class SimplePie_Rating
16013{
6d7d21a0 16014 /**
a6e043ff 16015 * Rating scheme
6d7d21a0 16016 *
a6e043ff
AD
16017 * @var string
16018 * @see get_scheme()
16019 */
16020 var $scheme;
16021
16022 /**
16023 * Rating value
16024 *
16025 * @var string
16026 * @see get_value()
16027 */
16028 var $value;
16029
16030 /**
16031 * Constructor, used to input the data
16032 *
16033 * For documentation on all the parameters, see the corresponding
16034 * properties and their accessors
6d7d21a0 16035 */
a6e043ff 16036 public function __construct($scheme = null, $value = null)
f2f7b699 16037 {
a6e043ff
AD
16038 $this->scheme = $scheme;
16039 $this->value = $value;
16040 }
6d7d21a0 16041
a6e043ff
AD
16042 /**
16043 * String-ified version
16044 *
16045 * @return string
16046 */
16047 public function __toString()
16048 {
16049 // There is no $this->data here
16050 return md5(serialize($this));
16051 }
16052
16053 /**
16054 * Get the organizational scheme for the rating
16055 *
16056 * @return string|null
16057 */
16058 public function get_scheme()
16059 {
16060 if ($this->scheme !== null)
16061 {
16062 return $this->scheme;
6d7d21a0
AD
16063 }
16064 else
16065 {
a6e043ff 16066 return null;
6d7d21a0 16067 }
f2f7b699
AD
16068 }
16069
6d7d21a0 16070 /**
a6e043ff 16071 * Get the value of the rating
6d7d21a0 16072 *
a6e043ff 16073 * @return string|null
6d7d21a0 16074 */
a6e043ff 16075 public function get_value()
f2f7b699 16076 {
a6e043ff 16077 if ($this->value !== null)
f2f7b699 16078 {
a6e043ff 16079 return $this->value;
6d7d21a0
AD
16080 }
16081 else
16082 {
a6e043ff 16083 return null;
f2f7b699 16084 }
f2f7b699 16085 }
6d7d21a0 16086}
f2f7b699 16087
6d7d21a0 16088/**
a6e043ff
AD
16089 * Handles creating objects and calling methods
16090 *
16091 * Access this via {@see SimplePie::get_registry()}
6d7d21a0
AD
16092 *
16093 * @package SimplePie
16094 */
a6e043ff 16095class SimplePie_Registry
6d7d21a0
AD
16096{
16097 /**
a6e043ff 16098 * Default class mapping
6d7d21a0 16099 *
a6e043ff
AD
16100 * Overriding classes *must* subclass these.
16101 *
16102 * @var array
6d7d21a0 16103 */
a6e043ff
AD
16104 protected $default = array(
16105 'Cache' => 'SimplePie_Cache',
16106 'Locator' => 'SimplePie_Locator',
16107 'Parser' => 'SimplePie_Parser',
16108 'File' => 'SimplePie_File',
16109 'Sanitize' => 'SimplePie_Sanitize',
16110 'Item' => 'SimplePie_Item',
16111 'Author' => 'SimplePie_Author',
16112 'Category' => 'SimplePie_Category',
16113 'Enclosure' => 'SimplePie_Enclosure',
16114 'Caption' => 'SimplePie_Caption',
16115 'Copyright' => 'SimplePie_Copyright',
16116 'Credit' => 'SimplePie_Credit',
16117 'Rating' => 'SimplePie_Rating',
16118 'Restriction' => 'SimplePie_Restriction',
16119 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
16120 'Source' => 'SimplePie_Source',
16121 'Misc' => 'SimplePie_Misc',
16122 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
16123 'Parse_Date' => 'SimplePie_Parse_Date',
16124 );
f954bd49 16125
6d7d21a0 16126 /**
a6e043ff 16127 * Class mapping
6d7d21a0 16128 *
a6e043ff
AD
16129 * @see register()
16130 * @var array
6d7d21a0 16131 */
a6e043ff 16132 protected $classes = array();
f954bd49 16133
6d7d21a0 16134 /**
a6e043ff 16135 * Legacy classes
6d7d21a0 16136 *
a6e043ff
AD
16137 * @see register()
16138 * @var array
6d7d21a0 16139 */
a6e043ff 16140 protected $legacy = array();
f954bd49 16141
a6e043ff
AD
16142 /**
16143 * Constructor
16144 *
16145 * No-op
16146 */
16147 public function __construct() { }
f954bd49 16148
f2f7b699 16149 /**
a6e043ff 16150 * Register a class
f2f7b699 16151 *
a6e043ff
AD
16152 * @param string $type See {@see $default} for names
16153 * @param string $class Class name, must subclass the corresponding default
16154 * @param bool $legacy Whether to enable legacy support for this class
16155 * @return bool Successfulness
f2f7b699 16156 */
a6e043ff 16157 public function register($type, $class, $legacy = false)
f2f7b699 16158 {
a6e043ff 16159 if (!is_subclass_of($class, $this->default[$type]))
f2f7b699 16160 {
a6e043ff 16161 return false;
f2f7b699 16162 }
a6e043ff
AD
16163
16164 $this->classes[$type] = $class;
16165
16166 if ($legacy)
f2f7b699 16167 {
a6e043ff 16168 $this->legacy[] = $class;
f2f7b699 16169 }
a6e043ff
AD
16170
16171 return true;
6d7d21a0 16172 }
f954bd49 16173
6d7d21a0 16174 /**
a6e043ff 16175 * Get the class registered for a type
6d7d21a0 16176 *
a6e043ff
AD
16177 * Where possible, use {@see create()} or {@see call()} instead
16178 *
16179 * @param string $type
16180 * @return string|null
6d7d21a0 16181 */
a6e043ff 16182 public function get_class($type)
6d7d21a0 16183 {
a6e043ff 16184 if (!empty($this->classes[$type]))
6d7d21a0 16185 {
a6e043ff 16186 return $this->classes[$type];
f2f7b699 16187 }
a6e043ff 16188 if (!empty($this->default[$type]))
f2f7b699 16189 {
a6e043ff 16190 return $this->default[$type];
f2f7b699 16191 }
a6e043ff
AD
16192
16193 return null;
f2f7b699 16194 }
f954bd49 16195
f2f7b699 16196 /**
a6e043ff 16197 * Create a new instance of a given type
f2f7b699 16198 *
a6e043ff
AD
16199 * @param string $type
16200 * @param array $parameters Parameters to pass to the constructor
16201 * @return object Instance of class
6d7d21a0 16202 */
a6e043ff 16203 public function &create($type, $parameters = array())
6d7d21a0 16204 {
a6e043ff
AD
16205 $class = $this->get_class($type);
16206
16207 if (in_array($class, $this->legacy))
6d7d21a0 16208 {
a6e043ff
AD
16209 switch ($type)
16210 {
16211 case 'locator':
16212 // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
16213 // Specified: file, timeout, useragent, max_checked_feeds
16214 $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
16215 array_splice($parameters, 3, 1, $replacement);
16216 break;
16217 }
6d7d21a0 16218 }
a6e043ff
AD
16219
16220 if (!method_exists($class, '__construct'))
6d7d21a0 16221 {
a6e043ff 16222 $instance = new $class;
6d7d21a0 16223 }
a6e043ff 16224 else
6d7d21a0 16225 {
a6e043ff
AD
16226 $reflector = new ReflectionClass($class);
16227 $instance = $reflector->newInstanceArgs($parameters);
6d7d21a0 16228 }
a6e043ff
AD
16229
16230 if (method_exists($instance, 'set_registry'))
6d7d21a0 16231 {
a6e043ff 16232 $instance->set_registry($this);
6d7d21a0 16233 }
a6e043ff 16234 return $instance;
6d7d21a0 16235 }
f954bd49 16236
f2f7b699 16237 /**
a6e043ff 16238 * Call a static method for a type
f2f7b699 16239 *
a6e043ff
AD
16240 * @param string $type
16241 * @param string $method
16242 * @param array $parameters
16243 * @return mixed
f2f7b699 16244 */
a6e043ff 16245 public function &call($type, $method, $parameters = array())
6d7d21a0 16246 {
a6e043ff 16247 $class = $this->get_class($type);
f954bd49 16248
a6e043ff 16249 if (in_array($class, $this->legacy))
6d7d21a0 16250 {
a6e043ff 16251 switch ($type)
6d7d21a0 16252 {
a6e043ff
AD
16253 case 'Cache':
16254 // For backwards compatibility with old non-static
16255 // Cache::create() methods
16256 if ($method === 'get_handler')
16257 {
16258 $result = @call_user_func_array(array($class, 'create'), $parameters);
16259 return $result;
16260 }
6d7d21a0 16261 break;
6d7d21a0
AD
16262 }
16263 }
f954bd49 16264
a6e043ff
AD
16265 $result = call_user_func_array(array($class, $method), $parameters);
16266 return $result;
6d7d21a0 16267 }
f2f7b699
AD
16268}
16269
16270/**
a6e043ff
AD
16271 * Handles `<media:restriction>` as defined in Media RSS
16272 *
16273 * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
16274 *
16275 * This class can be overloaded with {@see SimplePie::set_restriction_class()}
f2f7b699
AD
16276 *
16277 * @package SimplePie
a6e043ff 16278 * @subpackage API
f2f7b699 16279 */
a6e043ff 16280class SimplePie_Restriction
f2f7b699
AD
16281{
16282 /**
a6e043ff 16283 * Relationship ('allow'/'deny')
f2f7b699 16284 *
f2f7b699 16285 * @var string
a6e043ff 16286 * @see get_relationship()
f2f7b699 16287 */
a6e043ff 16288 var $relationship;
f954bd49 16289
6d7d21a0 16290 /**
a6e043ff 16291 * Type of restriction
6d7d21a0 16292 *
6d7d21a0 16293 * @var string
a6e043ff 16294 * @see get_type()
6d7d21a0 16295 */
a6e043ff 16296 var $type;
f954bd49 16297
6d7d21a0 16298 /**
a6e043ff 16299 * Restricted values
6d7d21a0 16300 *
a6e043ff
AD
16301 * @var string
16302 * @see get_value()
6d7d21a0 16303 */
a6e043ff 16304 var $value;
f2f7b699
AD
16305
16306 /**
a6e043ff 16307 * Constructor, used to input the data
f2f7b699 16308 *
a6e043ff
AD
16309 * For documentation on all the parameters, see the corresponding
16310 * properties and their accessors
f2f7b699 16311 */
a6e043ff
AD
16312 public function __construct($relationship = null, $type = null, $value = null)
16313 {
16314 $this->relationship = $relationship;
16315 $this->type = $type;
16316 $this->value = $value;
16317 }
f954bd49 16318
6d7d21a0 16319 /**
a6e043ff 16320 * String-ified version
6d7d21a0 16321 *
a6e043ff 16322 * @return string
6d7d21a0 16323 */
a6e043ff
AD
16324 public function __toString()
16325 {
16326 // There is no $this->data here
16327 return md5(serialize($this));
16328 }
f2f7b699
AD
16329
16330 /**
a6e043ff 16331 * Get the relationship
f2f7b699 16332 *
a6e043ff 16333 * @return string|null Either 'allow' or 'deny'
f2f7b699 16334 */
a6e043ff
AD
16335 public function get_relationship()
16336 {
16337 if ($this->relationship !== null)
16338 {
16339 return $this->relationship;
16340 }
16341 else
16342 {
16343 return null;
16344 }
16345 }
f2f7b699 16346
6d7d21a0 16347 /**
a6e043ff 16348 * Get the type
6d7d21a0 16349 *
a6e043ff 16350 * @return string|null
6d7d21a0 16351 */
a6e043ff
AD
16352 public function get_type()
16353 {
16354 if ($this->type !== null)
16355 {
16356 return $this->type;
16357 }
16358 else
16359 {
16360 return null;
16361 }
16362 }
16363
16364 /**
16365 * Get the list of restricted things
16366 *
16367 * @return string|null
16368 */
16369 public function get_value()
16370 {
16371 if ($this->value !== null)
16372 {
16373 return $this->value;
16374 }
16375 else
16376 {
16377 return null;
16378 }
16379 }
16380}
16381
16382/**
16383 * Used for data cleanup and post-processing
16384 *
16385 *
16386 * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
16387 *
16388 * @package SimplePie
16389 * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
16390 */
16391class SimplePie_Sanitize
16392{
16393 // Private vars
16394 var $base;
16395
16396 // Options
16397 var $remove_div = true;
16398 var $image_handler = '';
16399 var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
16400 var $encode_instead_of_strip = false;
16401 var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
16402 var $strip_comments = false;
16403 var $output_encoding = 'UTF-8';
16404 var $enable_cache = true;
16405 var $cache_location = './cache';
16406 var $cache_name_function = 'md5';
16407 var $timeout = 10;
16408 var $useragent = '';
16409 var $force_fsockopen = false;
16410 var $replace_url_attributes = null;
f954bd49 16411
a6e043ff 16412 public function __construct()
6d7d21a0 16413 {
a6e043ff
AD
16414 // Set defaults
16415 $this->set_url_replacements(null);
6d7d21a0
AD
16416 }
16417
a6e043ff 16418 public function remove_div($enable = true)
6d7d21a0 16419 {
a6e043ff
AD
16420 $this->remove_div = (bool) $enable;
16421 }
16422
16423 public function set_image_handler($page = false)
16424 {
16425 if ($page)
6d7d21a0 16426 {
a6e043ff 16427 $this->image_handler = (string) $page;
6d7d21a0
AD
16428 }
16429 else
16430 {
a6e043ff 16431 $this->image_handler = false;
6d7d21a0
AD
16432 }
16433 }
16434
a6e043ff 16435 public function set_registry(SimplePie_Registry $registry)
6d7d21a0 16436 {
a6e043ff 16437 $this->registry = $registry;
6d7d21a0 16438 }
f954bd49 16439
a6e043ff 16440 public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
6d7d21a0 16441 {
a6e043ff
AD
16442 if (isset($enable_cache))
16443 {
16444 $this->enable_cache = (bool) $enable_cache;
16445 }
16446
16447 if ($cache_location)
16448 {
16449 $this->cache_location = (string) $cache_location;
16450 }
16451
16452 if ($cache_name_function)
16453 {
16454 $this->cache_name_function = (string) $cache_name_function;
16455 }
6d7d21a0 16456 }
f954bd49 16457
a6e043ff 16458 public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
6d7d21a0 16459 {
a6e043ff 16460 if ($timeout)
6d7d21a0 16461 {
a6e043ff
AD
16462 $this->timeout = (string) $timeout;
16463 }
16464
16465 if ($useragent)
16466 {
16467 $this->useragent = (string) $useragent;
16468 }
16469
16470 if ($force_fsockopen)
16471 {
16472 $this->force_fsockopen = (string) $force_fsockopen;
16473 }
16474 }
16475
16476 public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
16477 {
16478 if ($tags)
16479 {
16480 if (is_array($tags))
6d7d21a0 16481 {
a6e043ff
AD
16482 $this->strip_htmltags = $tags;
16483 }
16484 else
16485 {
16486 $this->strip_htmltags = explode(',', $tags);
6d7d21a0
AD
16487 }
16488 }
a6e043ff
AD
16489 else
16490 {
16491 $this->strip_htmltags = false;
16492 }
6d7d21a0 16493 }
f954bd49 16494
a6e043ff 16495 public function encode_instead_of_strip($encode = false)
6d7d21a0 16496 {
a6e043ff
AD
16497 $this->encode_instead_of_strip = (bool) $encode;
16498 }
16499
16500 public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
16501 {
16502 if ($attribs)
6d7d21a0 16503 {
a6e043ff
AD
16504 if (is_array($attribs))
16505 {
16506 $this->strip_attributes = $attribs;
16507 }
16508 else
16509 {
16510 $this->strip_attributes = explode(',', $attribs);
16511 }
6d7d21a0
AD
16512 }
16513 else
16514 {
a6e043ff
AD
16515 $this->strip_attributes = false;
16516 }
16517 }
16518
16519 public function strip_comments($strip = false)
16520 {
16521 $this->strip_comments = (bool) $strip;
16522 }
16523
16524 public function set_output_encoding($encoding = 'UTF-8')
16525 {
16526 $this->output_encoding = (string) $encoding;
16527 }
16528
16529 /**
16530 * Set element/attribute key/value pairs of HTML attributes
16531 * containing URLs that need to be resolved relative to the feed
16532 *
16533 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
16534 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
16535 * |q|@cite
16536 *
16537 * @since 1.0
16538 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
16539 */
16540 public function set_url_replacements($element_attribute = null)
16541 {
16542 if ($element_attribute === null)
16543 {
16544 $element_attribute = array(
16545 'a' => 'href',
16546 'area' => 'href',
16547 'blockquote' => 'cite',
16548 'del' => 'cite',
16549 'form' => 'action',
16550 'img' => array(
16551 'longdesc',
16552 'src'
16553 ),
16554 'input' => 'src',
16555 'ins' => 'cite',
16556 'q' => 'cite'
16557 );
16558 }
16559 $this->replace_url_attributes = (array) $element_attribute;
16560 }
16561
16562 public function sanitize($data, $type, $base = '')
16563 {
16564 $data = trim($data);
16565 if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
16566 {
16567 if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
16568 {
16569 if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
16570 {
16571 $type |= SIMPLEPIE_CONSTRUCT_HTML;
16572 }
16573 else
16574 {
16575 $type |= SIMPLEPIE_CONSTRUCT_TEXT;
16576 }
16577 }
16578
16579 if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
16580 {
16581 $data = base64_decode($data);
16582 }
16583
16584 if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
16585 {
16586
16587 $document = new DOMDocument();
16588 $document->encoding = 'UTF-8';
16589 $data = $this->preprocess($data, $type);
16590
16591 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
16592 $document->loadHTML($data);
16593 restore_error_handler();
16594
16595 // Strip comments
16596 if ($this->strip_comments)
16597 {
16598 $xpath = new DOMXPath($document);
16599 $comments = $xpath->query('//comment()');
16600
16601 foreach ($comments as $comment)
16602 {
16603 $comment->parentNode->removeChild($comment);
16604 }
16605 }
16606
16607 // Strip out HTML tags and attributes that might cause various security problems.
16608 // Based on recommendations by Mark Pilgrim at:
16609 // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
16610 if ($this->strip_htmltags)
16611 {
16612 foreach ($this->strip_htmltags as $tag)
16613 {
16614 $this->strip_tag($tag, $document, $type);
16615 }
16616 }
16617
16618 if ($this->strip_attributes)
16619 {
16620 foreach ($this->strip_attributes as $attrib)
16621 {
16622 $this->strip_attr($attrib, $document);
16623 }
16624 }
16625
16626 // Replace relative URLs
16627 $this->base = $base;
16628 foreach ($this->replace_url_attributes as $element => $attributes)
16629 {
16630 $this->replace_urls($document, $element, $attributes);
16631 }
16632
16633 // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
16634 if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
16635 {
16636 $images = $document->getElementsByTagName('img');
16637 foreach ($images as $img)
16638 {
16639 if ($img->hasAttribute('src'))
16640 {
16641 $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
16642 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
16643
16644 if ($cache->load())
16645 {
16646 $img->setAttribute('src', $this->image_handler . $image_url);
16647 }
16648 else
16649 {
16650 $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
16651 $headers = $file->headers;
16652
16653 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
16654 {
16655 if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
16656 {
16657 $img->setAttribute('src', $this->image_handler . $image_url);
16658 }
16659 else
16660 {
16661 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
16662 }
16663 }
16664 }
16665 }
16666 }
16667 }
16668
16669 // Remove the DOCTYPE
16670 // Seems to cause segfaulting if we don't do this
16671 if ($document->firstChild instanceof DOMDocumentType)
16672 {
16673 $document->removeChild($document->firstChild);
16674 }
16675
16676 // Move everything from the body to the root
16677 $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
16678 $document->replaceChild($real_body, $document->firstChild);
16679
16680 // Finally, convert to a HTML string
16681 $data = trim($document->saveHTML());
16682
16683 if ($this->remove_div)
16684 {
16685 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
16686 $data = preg_replace('/<\/div>$/', '', $data);
16687 }
16688 else
16689 {
16690 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
16691 }
16692 }
16693
16694 if ($type & SIMPLEPIE_CONSTRUCT_IRI)
16695 {
16696 $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
16697 if ($absolute !== false)
16698 {
16699 $data = $absolute;
16700 }
16701 }
16702
16703 if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
16704 {
16705 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
16706 }
16707
16708 if ($this->output_encoding !== 'UTF-8')
16709 {
16710 $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
16711 }
6d7d21a0 16712 }
a6e043ff 16713 return $data;
6d7d21a0 16714 }
f954bd49 16715
a6e043ff 16716 protected function preprocess($html, $type)
f2f7b699 16717 {
a6e043ff
AD
16718 $ret = '';
16719 if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
6d7d21a0 16720 {
a6e043ff
AD
16721 // Atom XHTML constructs are wrapped with a div by default
16722 // Note: No protection if $html contains a stray </div>!
16723 $html = '<div>' . $html . '</div>';
16724 $ret .= '<!DOCTYPE html>';
16725 $content_type = 'text/html';
6d7d21a0
AD
16726 }
16727 else
16728 {
a6e043ff
AD
16729 $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
16730 $content_type = 'application/xhtml+xml';
6d7d21a0 16731 }
a6e043ff
AD
16732
16733 $ret .= '<html><head>';
16734 $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
16735 $ret .= '</head><body>' . $html . '</body></html>';
16736 return $ret;
f2f7b699 16737 }
f954bd49 16738
a6e043ff 16739 public function replace_urls($document, $tag, $attributes)
f2f7b699 16740 {
a6e043ff 16741 if (!is_array($attributes))
f2f7b699 16742 {
a6e043ff 16743 $attributes = array($attributes);
6d7d21a0 16744 }
a6e043ff
AD
16745
16746 if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
6d7d21a0 16747 {
a6e043ff
AD
16748 $elements = $document->getElementsByTagName($tag);
16749 foreach ($elements as $element)
16750 {
16751 foreach ($attributes as $attribute)
16752 {
16753 if ($element->hasAttribute($attribute))
16754 {
16755 $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
16756 if ($value !== false)
16757 {
16758 $element->setAttribute($attribute, $value);
16759 }
16760 }
16761 }
16762 }
f2f7b699 16763 }
f2f7b699 16764 }
f954bd49 16765
a6e043ff 16766 public function do_strip_htmltags($match)
f2f7b699 16767 {
a6e043ff 16768 if ($this->encode_instead_of_strip)
f2f7b699 16769 {
a6e043ff 16770 if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
6d7d21a0 16771 {
a6e043ff
AD
16772 $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
16773 $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
16774 return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
6d7d21a0
AD
16775 }
16776 else
16777 {
a6e043ff 16778 return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
6d7d21a0 16779 }
f2f7b699 16780 }
a6e043ff
AD
16781 elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
16782 {
16783 return $match[4];
16784 }
f2f7b699
AD
16785 else
16786 {
a6e043ff 16787 return '';
f2f7b699
AD
16788 }
16789 }
f954bd49 16790
a6e043ff 16791 protected function strip_tag($tag, $document, $type)
f2f7b699 16792 {
a6e043ff
AD
16793 $xpath = new DOMXPath($document);
16794 $elements = $xpath->query('body//' . $tag);
16795 if ($this->encode_instead_of_strip)
f2f7b699 16796 {
a6e043ff
AD
16797 foreach ($elements as $element)
16798 {
16799 $fragment = $document->createDocumentFragment();
16800
16801 // For elements which aren't script or style, include the tag itself
16802 if (!in_array($tag, array('script', 'style')))
16803 {
16804 $text = '<' . $tag;
16805 if ($element->hasAttributes())
16806 {
16807 $attrs = array();
16808 foreach ($element->attributes as $name => $attr)
16809 {
16810 $value = $attr->value;
16811
16812 // In XHTML, empty values should never exist, so we repeat the value
16813 if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
16814 {
16815 $value = $name;
16816 }
16817 // For HTML, empty is fine
16818 elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
16819 {
16820 $attrs[] = $name;
16821 continue;
16822 }
16823
16824 // Standard attribute text
16825 $attrs[] = $name . '="' . $attr->value . '"';
16826 }
16827 $text .= ' ' . implode(' ', $attrs);
16828 }
16829 $text .= '>';
16830 $fragment->appendChild(new DOMText($text));
16831 }
16832
16833 $number = $element->childNodes->length;
16834 for ($i = $number; $i > 0; $i--)
16835 {
16836 $child = $element->childNodes->item(0);
16837 $fragment->appendChild($child);
16838 }
16839
16840 if (!in_array($tag, array('script', 'style')))
16841 {
16842 $fragment->appendChild(new DOMText('</' . $tag . '>'));
16843 }
16844
16845 $element->parentNode->replaceChild($fragment, $element);
16846 }
16847
16848 return;
16849 }
16850 elseif (in_array($tag, array('script', 'style')))
16851 {
16852 foreach ($elements as $element)
16853 {
16854 $element->parentNode->removeChild($element);
16855 }
16856
16857 return;
f2f7b699
AD
16858 }
16859 else
16860 {
a6e043ff
AD
16861 foreach ($elements as $element)
16862 {
16863 $fragment = $document->createDocumentFragment();
16864 $number = $element->childNodes->length;
16865 for ($i = $number; $i > 0; $i--)
16866 {
16867 $child = $element->childNodes->item(0);
16868 $fragment->appendChild($child);
16869 }
16870
16871 $element->parentNode->replaceChild($fragment, $element);
16872 }
f2f7b699
AD
16873 }
16874 }
f954bd49 16875
a6e043ff 16876 protected function strip_attr($attrib, $document)
f2f7b699 16877 {
a6e043ff
AD
16878 $xpath = new DOMXPath($document);
16879 $elements = $xpath->query('//*[@' . $attrib . ']');
16880
16881 foreach ($elements as $element)
6d7d21a0 16882 {
a6e043ff 16883 $element->removeAttribute($attrib);
6d7d21a0 16884 }
f2f7b699 16885 }
a6e043ff
AD
16886}
16887
16888/**
16889 * Handles `<atom:source>`
16890 *
16891 * Used by {@see SimplePie_Item::get_source()}
16892 *
16893 * This class can be overloaded with {@see SimplePie::set_source_class()}
16894 *
16895 * @package SimplePie
16896 * @subpackage API
16897 */
16898class SimplePie_Source
16899{
16900 var $item;
16901 var $data = array();
16902 protected $registry;
f954bd49 16903
a6e043ff 16904 public function __construct($item, $data)
f2f7b699 16905 {
a6e043ff
AD
16906 $this->item = $item;
16907 $this->data = $data;
16908 }
16909
16910 public function set_registry(SimplePie_Registry $registry)
16911 {
16912 $this->registry = $registry;
16913 }
16914
16915 public function __toString()
16916 {
16917 return md5(serialize($this->data));
16918 }
16919
16920 public function get_source_tags($namespace, $tag)
16921 {
16922 if (isset($this->data['child'][$namespace][$tag]))
f2f7b699 16923 {
a6e043ff 16924 return $this->data['child'][$namespace][$tag];
6d7d21a0
AD
16925 }
16926 else
16927 {
a6e043ff 16928 return null;
6d7d21a0
AD
16929 }
16930 }
f954bd49 16931
a6e043ff 16932 public function get_base($element = array())
6d7d21a0 16933 {
a6e043ff
AD
16934 return $this->item->get_base($element);
16935 }
16936
16937 public function sanitize($data, $type, $base = '')
16938 {
16939 return $this->item->sanitize($data, $type, $base);
16940 }
16941
16942 public function get_item()
16943 {
16944 return $this->item;
16945 }
16946
16947 public function get_title()
16948 {
16949 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
6d7d21a0 16950 {
a6e043ff
AD
16951 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16952 }
16953 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
16954 {
16955 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16956 }
16957 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
16958 {
16959 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16960 }
16961 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
16962 {
16963 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16964 }
16965 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
16966 {
16967 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16968 }
16969 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
16970 {
16971 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
16972 }
16973 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
16974 {
16975 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0
AD
16976 }
16977 else
16978 {
a6e043ff 16979 return null;
6d7d21a0
AD
16980 }
16981 }
f954bd49 16982
a6e043ff 16983 public function get_category($key = 0)
6d7d21a0 16984 {
a6e043ff
AD
16985 $categories = $this->get_categories();
16986 if (isset($categories[$key]))
6d7d21a0 16987 {
a6e043ff 16988 return $categories[$key];
6d7d21a0
AD
16989 }
16990 else
16991 {
a6e043ff 16992 return null;
6d7d21a0
AD
16993 }
16994 }
f954bd49 16995
a6e043ff 16996 public function get_categories()
6d7d21a0 16997 {
a6e043ff
AD
16998 $categories = array();
16999
17000 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
6d7d21a0 17001 {
a6e043ff
AD
17002 $term = null;
17003 $scheme = null;
17004 $label = null;
17005 if (isset($category['attribs']['']['term']))
6d7d21a0 17006 {
a6e043ff 17007 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 17008 }
a6e043ff 17009 if (isset($category['attribs']['']['scheme']))
6d7d21a0 17010 {
a6e043ff 17011 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 17012 }
a6e043ff 17013 if (isset($category['attribs']['']['label']))
6d7d21a0 17014 {
a6e043ff 17015 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 17016 }
a6e043ff 17017 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
6d7d21a0 17018 }
a6e043ff 17019 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
6d7d21a0 17020 {
a6e043ff
AD
17021 // This is really the label, but keep this as the term also for BC.
17022 // Label will also work on retrieving because that falls back to term.
17023 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17024 if (isset($category['attribs']['']['domain']))
17025 {
17026 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
17027 }
17028 else
17029 {
17030 $scheme = null;
17031 }
17032 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
f2f7b699 17033 }
a6e043ff 17034 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
f2f7b699 17035 {
a6e043ff 17036 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
f2f7b699 17037 }
a6e043ff 17038 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
6d7d21a0 17039 {
a6e043ff 17040 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
6d7d21a0 17041 }
f2f7b699 17042
a6e043ff 17043 if (!empty($categories))
f2f7b699 17044 {
a6e043ff
AD
17045 return array_unique($categories);
17046 }
17047 else
17048 {
17049 return null;
f2f7b699 17050 }
a6e043ff 17051 }
f2f7b699 17052
a6e043ff
AD
17053 public function get_author($key = 0)
17054 {
17055 $authors = $this->get_authors();
17056 if (isset($authors[$key]))
f2f7b699 17057 {
a6e043ff
AD
17058 return $authors[$key];
17059 }
17060 else
17061 {
17062 return null;
f2f7b699 17063 }
a6e043ff 17064 }
f2f7b699 17065
a6e043ff
AD
17066 public function get_authors()
17067 {
17068 $authors = array();
17069 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
f2f7b699 17070 {
a6e043ff
AD
17071 $name = null;
17072 $uri = null;
17073 $email = null;
17074 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
f2f7b699 17075 {
a6e043ff 17076 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 17077 }
a6e043ff 17078 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
f2f7b699 17079 {
a6e043ff 17080 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
f2f7b699 17081 }
a6e043ff 17082 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
f2f7b699 17083 {
a6e043ff 17084 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 17085 }
a6e043ff 17086 if ($name !== null || $email !== null || $uri !== null)
f2f7b699 17087 {
a6e043ff 17088 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
f2f7b699
AD
17089 }
17090 }
a6e043ff 17091 if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
f2f7b699 17092 {
a6e043ff
AD
17093 $name = null;
17094 $url = null;
17095 $email = null;
17096 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
6d7d21a0 17097 {
a6e043ff 17098 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 17099 }
a6e043ff 17100 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
6d7d21a0 17101 {
a6e043ff
AD
17102 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
17103 }
17104 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17105 {
17106 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17107 }
17108 if ($name !== null || $email !== null || $url !== null)
17109 {
17110 $authors[] = $this->registry->create('Author', array($name, $url, $email));
6d7d21a0 17111 }
f2f7b699 17112 }
a6e043ff 17113 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
f2f7b699 17114 {
a6e043ff
AD
17115 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17116 }
17117 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
17118 {
17119 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17120 }
17121 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
17122 {
17123 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17124 }
17125
17126 if (!empty($authors))
17127 {
17128 return array_unique($authors);
f2f7b699
AD
17129 }
17130 else
17131 {
a6e043ff 17132 return null;
f2f7b699 17133 }
6d7d21a0
AD
17134 }
17135
a6e043ff 17136 public function get_contributor($key = 0)
6d7d21a0 17137 {
a6e043ff
AD
17138 $contributors = $this->get_contributors();
17139 if (isset($contributors[$key]))
f2f7b699 17140 {
a6e043ff
AD
17141 return $contributors[$key];
17142 }
17143 else
17144 {
17145 return null;
f2f7b699
AD
17146 }
17147 }
17148
a6e043ff 17149 public function get_contributors()
f2f7b699 17150 {
a6e043ff
AD
17151 $contributors = array();
17152 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
f2f7b699 17153 {
a6e043ff
AD
17154 $name = null;
17155 $uri = null;
17156 $email = null;
17157 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
f2f7b699 17158 {
a6e043ff 17159 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 17160 }
a6e043ff 17161 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
f2f7b699 17162 {
a6e043ff
AD
17163 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
17164 }
17165 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
17166 {
17167 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17168 }
17169 if ($name !== null || $email !== null || $uri !== null)
17170 {
17171 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
17172 }
17173 }
17174 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
17175 {
17176 $name = null;
17177 $url = null;
17178 $email = null;
17179 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
17180 {
17181 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17182 }
17183 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
17184 {
17185 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
17186 }
17187 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17188 {
17189 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17190 }
17191 if ($name !== null || $email !== null || $url !== null)
17192 {
17193 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
f2f7b699
AD
17194 }
17195 }
a5ae3915 17196
a6e043ff 17197 if (!empty($contributors))
a5ae3915 17198 {
a6e043ff 17199 return array_unique($contributors);
a5ae3915 17200 }
a6e043ff
AD
17201 else
17202 {
a5ae3915
MK
17203 return null;
17204 }
f2f7b699
AD
17205 }
17206
a6e043ff 17207 public function get_link($key = 0, $rel = 'alternate')
f2f7b699 17208 {
a6e043ff
AD
17209 $links = $this->get_links($rel);
17210 if (isset($links[$key]))
f2f7b699 17211 {
a6e043ff 17212 return $links[$key];
f2f7b699 17213 }
a6e043ff 17214 else
f2f7b699 17215 {
a6e043ff 17216 return null;
f2f7b699 17217 }
f2f7b699
AD
17218 }
17219
a6e043ff
AD
17220 /**
17221 * Added for parity between the parent-level and the item/entry-level.
17222 */
17223 public function get_permalink()
17224 {
17225 return $this->get_link(0);
17226 }
17227
17228 public function get_links($rel = 'alternate')
f2f7b699 17229 {
a6e043ff 17230 if (!isset($this->data['links']))
f2f7b699 17231 {
a6e043ff
AD
17232 $this->data['links'] = array();
17233 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
f2f7b699 17234 {
a6e043ff 17235 foreach ($links as $link)
f2f7b699 17236 {
a6e043ff
AD
17237 if (isset($link['attribs']['']['href']))
17238 {
17239 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
17240 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
17241 }
f2f7b699 17242 }
a6e043ff
AD
17243 }
17244 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
17245 {
17246 foreach ($links as $link)
f2f7b699 17247 {
a6e043ff
AD
17248 if (isset($link['attribs']['']['href']))
17249 {
17250 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
17251 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
17252
17253 }
f2f7b699
AD
17254 }
17255 }
a6e043ff 17256 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
f2f7b699 17257 {
a6e043ff 17258 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
f2f7b699 17259 }
a6e043ff
AD
17260 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
17261 {
17262 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17263 }
17264 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
17265 {
17266 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17267 }
17268
17269 $keys = array_keys($this->data['links']);
17270 foreach ($keys as $key)
f2f7b699 17271 {
a6e043ff 17272 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
f2f7b699 17273 {
a6e043ff
AD
17274 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
17275 {
17276 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
17277 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
17278 }
17279 else
17280 {
17281 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
17282 }
f2f7b699 17283 }
a6e043ff 17284 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
f2f7b699 17285 {
a6e043ff 17286 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
f2f7b699 17287 }
a6e043ff 17288 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
f2f7b699
AD
17289 }
17290 }
f2f7b699 17291
a6e043ff 17292 if (isset($this->data['links'][$rel]))
f2f7b699 17293 {
a6e043ff 17294 return $this->data['links'][$rel];
f2f7b699
AD
17295 }
17296 else
17297 {
a6e043ff 17298 return null;
f2f7b699 17299 }
a6e043ff 17300 }
f2f7b699 17301
a6e043ff
AD
17302 public function get_description()
17303 {
17304 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
f2f7b699 17305 {
a6e043ff 17306 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
f2f7b699 17307 }
a6e043ff 17308 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
f2f7b699 17309 {
a6e043ff 17310 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
f2f7b699 17311 }
a6e043ff 17312 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
f2f7b699 17313 {
a6e043ff 17314 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
f2f7b699 17315 }
a6e043ff 17316 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
f2f7b699 17317 {
a6e043ff 17318 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
f2f7b699 17319 }
a6e043ff 17320 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
f2f7b699 17321 {
a6e043ff 17322 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
f2f7b699 17323 }
a6e043ff 17324 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
6d7d21a0 17325 {
a6e043ff 17326 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6d7d21a0 17327 }
a6e043ff 17328 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
a5ae3915 17329 {
a6e043ff 17330 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
a5ae3915 17331 }
a6e043ff 17332 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
a5ae3915 17333 {
a6e043ff
AD
17334 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
17335 }
17336 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
17337 {
17338 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
a5ae3915
MK
17339 }
17340 else
17341 {
a6e043ff 17342 return null;
a5ae3915 17343 }
f2f7b699
AD
17344 }
17345
a6e043ff 17346 public function get_copyright()
f2f7b699 17347 {
a6e043ff
AD
17348 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
17349 {
17350 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17351 }
17352 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
17353 {
17354 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17355 }
17356 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
17357 {
17358 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17359 }
17360 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
17361 {
17362 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17363 }
17364 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
17365 {
17366 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17367 }
17368 else
17369 {
17370 return null;
17371 }
f2f7b699
AD
17372 }
17373
a6e043ff 17374 public function get_language()
f2f7b699 17375 {
a6e043ff 17376 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
f2f7b699 17377 {
a6e043ff 17378 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 17379 }
a6e043ff 17380 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
f2f7b699 17381 {
a6e043ff 17382 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 17383 }
a6e043ff 17384 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
f2f7b699 17385 {
a6e043ff 17386 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699 17387 }
a6e043ff 17388 elseif (isset($this->data['xml_lang']))
f2f7b699 17389 {
a6e043ff 17390 return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
f2f7b699
AD
17391 }
17392 else
17393 {
a6e043ff 17394 return null;
f2f7b699 17395 }
a6e043ff 17396 }
f2f7b699 17397
a6e043ff
AD
17398 public function get_latitude()
17399 {
17400 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
f2f7b699 17401 {
a6e043ff
AD
17402 return (float) $return[0]['data'];
17403 }
17404 elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
17405 {
17406 return (float) $match[1];
f2f7b699
AD
17407 }
17408 else
17409 {
a6e043ff 17410 return null;
f2f7b699
AD
17411 }
17412 }
17413
a6e043ff 17414 public function get_longitude()
f2f7b699 17415 {
a6e043ff 17416 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
f2f7b699 17417 {
a6e043ff
AD
17418 return (float) $return[0]['data'];
17419 }
17420 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
17421 {
17422 return (float) $return[0]['data'];
17423 }
17424 elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
17425 {
17426 return (float) $match[2];
f2f7b699 17427 }
a5ae3915 17428 else
f2f7b699 17429 {
a6e043ff 17430 return null;
f2f7b699
AD
17431 }
17432 }
17433
a6e043ff 17434 public function get_image_url()
f2f7b699 17435 {
a6e043ff 17436 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
f2f7b699 17437 {
a6e043ff 17438 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
f2f7b699 17439 }
a6e043ff 17440 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
f2f7b699 17441 {
a6e043ff 17442 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
f2f7b699 17443 }
a6e043ff 17444 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
f2f7b699 17445 {
a6e043ff
AD
17446 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
17447 }
17448 else
17449 {
17450 return null;
f2f7b699 17451 }
f2f7b699
AD
17452 }
17453}
17454
17455/**
a6e043ff
AD
17456 * Parses the XML Declaration
17457 *
17458 * @package SimplePie
17459 * @subpackage Parsing
f2f7b699 17460 */
a6e043ff 17461class SimplePie_XML_Declaration_Parser
f2f7b699 17462{
a6e043ff
AD
17463 /**
17464 * XML Version
17465 *
17466 * @access public
17467 * @var string
17468 */
17469 var $version = '1.0';
f2f7b699 17470
a6e043ff
AD
17471 /**
17472 * Encoding
17473 *
17474 * @access public
17475 * @var string
17476 */
17477 var $encoding = 'UTF-8';
f2f7b699 17478
a6e043ff
AD
17479 /**
17480 * Standalone
17481 *
17482 * @access public
17483 * @var bool
17484 */
17485 var $standalone = false;
17486
17487 /**
17488 * Current state of the state machine
17489 *
17490 * @access private
17491 * @var string
17492 */
17493 var $state = 'before_version_name';
17494
17495 /**
17496 * Input data
17497 *
17498 * @access private
17499 * @var string
17500 */
17501 var $data = '';
17502
17503 /**
17504 * Input data length (to avoid calling strlen() everytime this is needed)
17505 *
17506 * @access private
17507 * @var int
17508 */
17509 var $data_length = 0;
17510
17511 /**
17512 * Current position of the pointer
17513 *
17514 * @var int
17515 * @access private
17516 */
17517 var $position = 0;
f2f7b699 17518
a6e043ff
AD
17519 /**
17520 * Create an instance of the class with the input data
17521 *
17522 * @access public
17523 * @param string $data Input data
17524 */
17525 public function __construct($data)
f2f7b699 17526 {
a6e043ff
AD
17527 $this->data = $data;
17528 $this->data_length = strlen($this->data);
f2f7b699
AD
17529 }
17530
a6e043ff
AD
17531 /**
17532 * Parse the input data
17533 *
17534 * @access public
17535 * @return bool true on success, false on failure
17536 */
17537 public function parse()
f2f7b699 17538 {
a6e043ff 17539 while ($this->state && $this->state !== 'emit' && $this->has_data())
f2f7b699 17540 {
a6e043ff
AD
17541 $state = $this->state;
17542 $this->$state();
17543 }
17544 $this->data = '';
17545 if ($this->state === 'emit')
17546 {
17547 return true;
f2f7b699
AD
17548 }
17549 else
17550 {
a6e043ff
AD
17551 $this->version = '';
17552 $this->encoding = '';
17553 $this->standalone = '';
17554 return false;
f2f7b699
AD
17555 }
17556 }
17557
a6e043ff
AD
17558 /**
17559 * Check whether there is data beyond the pointer
17560 *
17561 * @access private
17562 * @return bool true if there is further data, false if not
17563 */
17564 public function has_data()
f2f7b699 17565 {
a6e043ff
AD
17566 return (bool) ($this->position < $this->data_length);
17567 }
f2f7b699 17568
a6e043ff
AD
17569 /**
17570 * Advance past any whitespace
17571 *
17572 * @return int Number of whitespace characters passed
17573 */
17574 public function skip_whitespace()
17575 {
17576 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
17577 $this->position += $whitespace;
17578 return $whitespace;
17579 }
17580
17581 /**
17582 * Read value
17583 */
17584 public function get_value()
17585 {
17586 $quote = substr($this->data, $this->position, 1);
17587 if ($quote === '"' || $quote === "'")
f2f7b699 17588 {
a6e043ff
AD
17589 $this->position++;
17590 $len = strcspn($this->data, $quote, $this->position);
17591 if ($this->has_data())
17592 {
17593 $value = substr($this->data, $this->position, $len);
17594 $this->position += $len + 1;
17595 return $value;
17596 }
f2f7b699 17597 }
a6e043ff
AD
17598 return false;
17599 }
f2f7b699 17600
a6e043ff
AD
17601 public function before_version_name()
17602 {
17603 if ($this->skip_whitespace())
f2f7b699 17604 {
a6e043ff 17605 $this->state = 'version_name';
f2f7b699 17606 }
a6e043ff 17607 else
f2f7b699 17608 {
a6e043ff 17609 $this->state = false;
f2f7b699
AD
17610 }
17611 }
17612
a6e043ff 17613 public function version_name()
f2f7b699 17614 {
a6e043ff 17615 if (substr($this->data, $this->position, 7) === 'version')
f2f7b699 17616 {
a6e043ff
AD
17617 $this->position += 7;
17618 $this->skip_whitespace();
17619 $this->state = 'version_equals';
f2f7b699 17620 }
a6e043ff 17621 else
f2f7b699 17622 {
a6e043ff 17623 $this->state = false;
f2f7b699 17624 }
a6e043ff 17625 }
f2f7b699 17626
a6e043ff
AD
17627 public function version_equals()
17628 {
17629 if (substr($this->data, $this->position, 1) === '=')
f2f7b699 17630 {
a6e043ff
AD
17631 $this->position++;
17632 $this->skip_whitespace();
17633 $this->state = 'version_value';
f2f7b699 17634 }
a6e043ff 17635 else
f2f7b699 17636 {
a6e043ff 17637 $this->state = false;
f2f7b699
AD
17638 }
17639 }
17640
a6e043ff 17641 public function version_value()
f2f7b699 17642 {
a6e043ff 17643 if ($this->version = $this->get_value())
f2f7b699 17644 {
a6e043ff
AD
17645 $this->skip_whitespace();
17646 if ($this->has_data())
f2f7b699 17647 {
a6e043ff 17648 $this->state = 'encoding_name';
f2f7b699
AD
17649 }
17650 else
17651 {
a6e043ff 17652 $this->state = 'emit';
f2f7b699
AD
17653 }
17654 }
17655 else
17656 {
a6e043ff 17657 $this->state = false;
f2f7b699
AD
17658 }
17659 }
17660
a6e043ff 17661 public function encoding_name()
f2f7b699 17662 {
a6e043ff
AD
17663 if (substr($this->data, $this->position, 8) === 'encoding')
17664 {
17665 $this->position += 8;
17666 $this->skip_whitespace();
17667 $this->state = 'encoding_equals';
17668 }
17669 else
17670 {
17671 $this->state = 'standalone_name';
17672 }
f2f7b699
AD
17673 }
17674
a6e043ff 17675 public function encoding_equals()
f2f7b699 17676 {
a6e043ff 17677 if (substr($this->data, $this->position, 1) === '=')
f2f7b699 17678 {
a6e043ff
AD
17679 $this->position++;
17680 $this->skip_whitespace();
17681 $this->state = 'encoding_value';
17682 }
17683 else
17684 {
17685 $this->state = false;
17686 }
17687 }
17688
17689 public function encoding_value()
17690 {
17691 if ($this->encoding = $this->get_value())
17692 {
17693 $this->skip_whitespace();
17694 if ($this->has_data())
f2f7b699 17695 {
a6e043ff 17696 $this->state = 'standalone_name';
f2f7b699
AD
17697 }
17698 else
17699 {
a6e043ff 17700 $this->state = 'emit';
f2f7b699
AD
17701 }
17702 }
17703 else
17704 {
a6e043ff 17705 $this->state = false;
f2f7b699
AD
17706 }
17707 }
17708
a6e043ff 17709 public function standalone_name()
f2f7b699 17710 {
a6e043ff
AD
17711 if (substr($this->data, $this->position, 10) === 'standalone')
17712 {
17713 $this->position += 10;
17714 $this->skip_whitespace();
17715 $this->state = 'standalone_equals';
17716 }
17717 else
17718 {
17719 $this->state = false;
17720 }
f2f7b699
AD
17721 }
17722
a6e043ff 17723 public function standalone_equals()
f2f7b699 17724 {
a6e043ff 17725 if (substr($this->data, $this->position, 1) === '=')
f2f7b699 17726 {
a6e043ff
AD
17727 $this->position++;
17728 $this->skip_whitespace();
17729 $this->state = 'standalone_value';
17730 }
17731 else
17732 {
17733 $this->state = false;
f2f7b699 17734 }
f2f7b699
AD
17735 }
17736
a6e043ff 17737 public function standalone_value()
f2f7b699 17738 {
a6e043ff 17739 if ($standalone = $this->get_value())
f2f7b699 17740 {
a6e043ff 17741 switch ($standalone)
f2f7b699 17742 {
a6e043ff
AD
17743 case 'yes':
17744 $this->standalone = true;
17745 break;
17746
17747 case 'no':
17748 $this->standalone = false;
17749 break;
17750
17751 default:
17752 $this->state = false;
17753 return;
f2f7b699 17754 }
f2f7b699 17755
a6e043ff
AD
17756 $this->skip_whitespace();
17757 if ($this->has_data())
f2f7b699 17758 {
a6e043ff 17759 $this->state = false;
f2f7b699
AD
17760 }
17761 else
17762 {
a6e043ff 17763 $this->state = 'emit';
f2f7b699
AD
17764 }
17765 }
f2f7b699
AD
17766 else
17767 {
a6e043ff 17768 $this->state = false;
f2f7b699
AD
17769 }
17770 }
17771}
17772