PEEL Shopping
Open source ecommerce : PEEL Shopping
Simplepie.php
Go to the documentation of this file.
1 <?php
48 define('SIMPLEPIE_NAME', 'SimplePie');
49 define('SIMPLEPIE_VERSION', '1.3.1');
50 define('SIMPLEPIE_BUILD', '20121030175911');
51 define('SIMPLEPIE_URL', 'http://simplepie.org');
52 define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
53 define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
54 define('SIMPLEPIE_LOCATOR_NONE', 0);
55 define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
56 define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
57 define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
58 define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
59 define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
60 define('SIMPLEPIE_LOCATOR_ALL', 31);
61 define('SIMPLEPIE_TYPE_NONE', 0);
62 define('SIMPLEPIE_TYPE_RSS_090', 1);
63 define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
64 define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
65 define('SIMPLEPIE_TYPE_RSS_091', 6);
66 define('SIMPLEPIE_TYPE_RSS_092', 8);
67 define('SIMPLEPIE_TYPE_RSS_093', 16);
68 define('SIMPLEPIE_TYPE_RSS_094', 32);
69 define('SIMPLEPIE_TYPE_RSS_10', 64);
70 define('SIMPLEPIE_TYPE_RSS_20', 128);
71 define('SIMPLEPIE_TYPE_RSS_RDF', 65);
72 define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
73 define('SIMPLEPIE_TYPE_RSS_ALL', 255);
74 define('SIMPLEPIE_TYPE_ATOM_03', 256);
75 define('SIMPLEPIE_TYPE_ATOM_10', 512);
76 define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
77 define('SIMPLEPIE_TYPE_ALL', 1023);
78 define('SIMPLEPIE_CONSTRUCT_NONE', 0);
79 define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
80 define('SIMPLEPIE_CONSTRUCT_HTML', 2);
81 define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
82 define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
83 define('SIMPLEPIE_CONSTRUCT_IRI', 16);
84 define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
85 define('SIMPLEPIE_CONSTRUCT_ALL', 63);
86 define('SIMPLEPIE_SAME_CASE', 1);
87 define('SIMPLEPIE_LOWERCASE', 2);
88 define('SIMPLEPIE_UPPERCASE', 4);
89 define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
90 define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
91 define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
92 define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
93 define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
94 define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
95 define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
96 define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
97 define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
98 define('SIMPLEPIE_NAMESPACE_RSS_20', '');
99 define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
100 define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
101 define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
102 define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
103 define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
104 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
105 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
106 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
107 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
108 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
109 define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
110 define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
111 define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
112 define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
113 define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
114 define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
115 define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
116 define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
117 define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
119 {
120 
121  public $data = array();
122 
123  public $error;
124 
125  public $sanitize;
126 
128 
129  public $feed_url;
130 
131  public $file;
132 
133  public $raw_data;
134 
135  public $timeout = 10;
136 
137  public $force_fsockopen = false;
138 
139  public $force_feed = false;
140 
141  public $cache = true;
142 
143  public $cache_duration = 3600;
144 
145  public $autodiscovery_cache_duration = 604800; // 7 Days.
146 
147  public $cache_location = './cache';
148 
149  public $cache_name_function = 'md5';
150 
151  public $order_by_date = true;
152 
153  public $input_encoding = false;
154 
156 
157  public $registry;
158 
159  public $max_checked_feeds = 10;
160 
161  public $all_discovered_feeds = array();
162 
163  public $image_handler = '';
164 
165  public $multifeed_url = array();
166 
167  public $multifeed_objects = array();
168 
169  public $config_settings = null;
170 
171  public $item_limit = 0;
172 
173  public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
174 
175  public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
176 
177  public function __construct()
178  {
179  if (version_compare(PHP_VERSION, '5.2', '<'))
180  {
181  trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
182  die();
183  }
184  // Other objects, instances created here so we can set options on them
185  $this->sanitize = new SimplePie_Sanitize();
186  $this->registry = new SimplePie_Registry();
187  if (func_num_args() > 0)
188  {
189  $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
190  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);
191  $args = func_get_args();
192  switch (count($args)) {
193  case 3:
194  $this->set_cache_duration($args[2]);
195  case 2:
196  $this->set_cache_location($args[1]);
197  case 1:
198  $this->set_feed_url($args[0]);
199  $this->init();
200  }
201  }
202  }
203 
204  public function __toString()
205  {
206  return md5(serialize($this->data));
207  }
208 
209  public function __destruct()
210  {
211  if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
212  {
213  if (!empty($this->data['items']))
214  {
215  foreach ($this->data['items'] as $item)
216  {
217  $item->__destruct();
218  }
219  unset($item, $this->data['items']);
220  }
221  if (!empty($this->data['ordered_items']))
222  {
223  foreach ($this->data['ordered_items'] as $item)
224  {
225  $item->__destruct();
226  }
227  unset($item, $this->data['ordered_items']);
228  }
229  }
230  }
231 
232  public function force_feed($enable = false)
233  {
234  $this->force_feed = (bool) $enable;
235  }
236 
237  public function set_feed_url($url)
238  {
239  $this->multifeed_url = array();
240  if (is_array($url))
241  {
242  foreach ($url as $value)
243  {
244  $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
245  }
246  }
247  else
248  {
249  $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
250  }
251  }
252 
253  public function set_file(&$file)
254  {
255  if ($file instanceof SimplePie_File)
256  {
257  $this->feed_url = $file->url;
258  $this->file =& $file;
259  return true;
260  }
261  return false;
262  }
263 
264  public function set_raw_data($data)
265  {
266  $this->raw_data = $data;
267  }
268 
269  public function set_timeout($timeout = 10)
270  {
271  $this->timeout = (int) $timeout;
272  }
273 
274  public function force_fsockopen($enable = false)
275  {
276  $this->force_fsockopen = (bool) $enable;
277  }
278 
279  public function enable_cache($enable = true)
280  {
281  $this->cache = (bool) $enable;
282  }
283 
284  public function set_cache_duration($seconds = 3600)
285  {
286  $this->cache_duration = (int) $seconds;
287  }
288 
289  public function set_autodiscovery_cache_duration($seconds = 604800)
290  {
291  $this->autodiscovery_cache_duration = (int) $seconds;
292  }
293 
294  public function set_cache_location($location = './cache')
295  {
296  $this->cache_location = (string) $location;
297  }
298 
299  public function enable_order_by_date($enable = true)
300  {
301  $this->order_by_date = (bool) $enable;
302  }
303 
304  public function set_input_encoding($encoding = false)
305  {
306  if ($encoding)
307  {
308  $this->input_encoding = (string) $encoding;
309  }
310  else
311  {
312  $this->input_encoding = false;
313  }
314  }
315 
317  {
318  $this->autodiscovery = (int) $level;
319  }
320 
321  public function &get_registry()
322  {
323  return $this->registry;
324  }
325 
326 
327  public function set_cache_class($class = 'SimplePie_Cache')
328  {
329  return $this->registry->register('Cache', $class, true);
330  }
331 
332  public function set_locator_class($class = 'SimplePie_Locator')
333  {
334  return $this->registry->register('Locator', $class, true);
335  }
336 
337  public function set_parser_class($class = 'SimplePie_Parser')
338  {
339  return $this->registry->register('Parser', $class, true);
340  }
341 
342  public function set_file_class($class = 'SimplePie_File')
343  {
344  return $this->registry->register('File', $class, true);
345  }
346 
347  public function set_sanitize_class($class = 'SimplePie_Sanitize')
348  {
349  return $this->registry->register('Sanitize', $class, true);
350  }
351 
352  public function set_item_class($class = 'SimplePie_Item')
353  {
354  return $this->registry->register('Item', $class, true);
355  }
356 
357  public function set_author_class($class = 'SimplePie_Author')
358  {
359  return $this->registry->register('Author', $class, true);
360  }
361 
362  public function set_category_class($class = 'SimplePie_Category')
363  {
364  return $this->registry->register('Category', $class, true);
365  }
366 
367  public function set_enclosure_class($class = 'SimplePie_Enclosure')
368  {
369  return $this->registry->register('Enclosure', $class, true);
370  }
371 
372  public function set_caption_class($class = 'SimplePie_Caption')
373  {
374  return $this->registry->register('Caption', $class, true);
375  }
376 
377  public function set_copyright_class($class = 'SimplePie_Copyright')
378  {
379  return $this->registry->register('Copyright', $class, true);
380  }
381 
382  public function set_credit_class($class = 'SimplePie_Credit')
383  {
384  return $this->registry->register('Credit', $class, true);
385  }
386 
387  public function set_rating_class($class = 'SimplePie_Rating')
388  {
389  return $this->registry->register('Rating', $class, true);
390  }
391 
392  public function set_restriction_class($class = 'SimplePie_Restriction')
393  {
394  return $this->registry->register('Restriction', $class, true);
395  }
396 
397  public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
398  {
399  return $this->registry->register('Content_Type_Sniffer', $class, true);
400  }
401 
402  public function set_source_class($class = 'SimplePie_Source')
403  {
404  return $this->registry->register('Source', $class, true);
405  }
406 
407 
408  public function set_useragent($ua = SIMPLEPIE_USERAGENT)
409  {
410  $this->useragent = (string) $ua;
411  }
412 
413  public function set_cache_name_function($function = 'md5')
414  {
415  if (is_callable($function))
416  {
417  $this->cache_name_function = $function;
418  }
419  }
420 
421  public function set_stupidly_fast($set = false)
422  {
423  if ($set)
424  {
425  $this->enable_order_by_date(false);
426  $this->remove_div(false);
427  $this->strip_comments(false);
428  $this->strip_htmltags(false);
429  $this->strip_attributes(false);
430  $this->set_image_handler(false);
431  }
432  }
433 
434  public function set_max_checked_feeds($max = 10)
435  {
436  $this->max_checked_feeds = (int) $max;
437  }
438  public function remove_div($enable = true)
439  {
440  $this->sanitize->remove_div($enable);
441  }
442  public function strip_htmltags($tags = '', $encode = null)
443  {
444  if ($tags === '')
445  {
446  $tags = $this->strip_htmltags;
447  }
448  $this->sanitize->strip_htmltags($tags);
449  if ($encode !== null)
450  {
451  $this->sanitize->encode_instead_of_strip($tags);
452  }
453  }
454  public function encode_instead_of_strip($enable = true)
455  {
456  $this->sanitize->encode_instead_of_strip($enable);
457  }
458  public function strip_attributes($attribs = '')
459  {
460  if ($attribs === '')
461  {
462  $attribs = $this->strip_attributes;
463  }
464  $this->sanitize->strip_attributes($attribs);
465  }
466 
467  public function set_output_encoding($encoding = 'UTF-8')
468  {
469  $this->sanitize->set_output_encoding($encoding);
470  }
471  public function strip_comments($strip = false)
472  {
473  $this->sanitize->strip_comments($strip);
474  }
475 
476  public function set_url_replacements($element_attribute = null)
477  {
478  $this->sanitize->set_url_replacements($element_attribute);
479  }
480 
481  public function set_image_handler($page = false, $qs = 'i')
482  {
483  if ($page !== false)
484  {
485  $this->sanitize->set_image_handler($page . '?' . $qs . '=');
486  }
487  else
488  {
489  $this->image_handler = '';
490  }
491  }
492 
493  public function set_item_limit($limit = 0)
494  {
495  $this->item_limit = (int) $limit;
496  }
497 
498  public function init()
499  {
500  // Check absolute bare minimum requirements.
501  if (!extension_loaded('xml') || !extension_loaded('pcre'))
502  {
503  return false;
504  }
505  // 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.
506  elseif (!extension_loaded('xmlreader'))
507  {
508  static $xml_is_sane = null;
509  if ($xml_is_sane === null)
510  {
511  $parser_check = xml_parser_create();
512  xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
513  xml_parser_free($parser_check);
514  $xml_is_sane = isset($values[0]['value']);
515  }
516  if (!$xml_is_sane)
517  {
518  return false;
519  }
520  }
521  if (method_exists($this->sanitize, 'set_registry'))
522  {
523  $this->sanitize->set_registry($this->registry);
524  }
525  // Pass whatever was set with config options over to the sanitizer.
526  // Pass the classes in for legacy support; new classes should use the registry instead
527  $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
528  $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
529  if (!empty($this->multifeed_url))
530  {
531  $i = 0;
532  $success = 0;
533  $this->multifeed_objects = array();
534  $this->error = array();
535  foreach ($this->multifeed_url as $url)
536  {
537  $this->multifeed_objects[$i] = clone $this;
538  $this->multifeed_objects[$i]->set_feed_url($url);
539  $single_success = $this->multifeed_objects[$i]->init();
540  $success |= $single_success;
541  if (!$single_success)
542  {
543  $this->error[$i] = $this->multifeed_objects[$i]->error();
544  }
545  $i++;
546  }
547  return (bool) $success;
548  }
549  elseif ($this->feed_url === null && $this->raw_data === null)
550  {
551  return false;
552  }
553  $this->error = null;
554  $this->data = array();
555  $this->multifeed_objects = array();
556  $cache = false;
557  if ($this->feed_url !== null)
558  {
559  $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
560  // Decide whether to enable caching
561  if ($this->cache && $parsed_feed_url['scheme'] !== '')
562  {
563  $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
564  }
565  // Fetch the data via SimplePie_File into $this->raw_data
566  if (($fetched = $this->fetch_data($cache)) === true)
567  {
568  return true;
569  }
570  elseif ($fetched === false) {
571  return false;
572  }
573  list($headers, $sniffed) = $fetched;
574  }
575  // Set up array of possible encodings
576  $encodings = array();
577  // First check to see if input has been overridden.
578  if ($this->input_encoding !== false)
579  {
580  $encodings[] = $this->input_encoding;
581  }
582  $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
583  $text_types = array('text/xml', 'text/xml-external-parsed-entity');
584  // RFC 3023 (only applies to sniffed content)
585  if (isset($sniffed))
586  {
587  if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
588  {
589  if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
590  {
591  $encodings[] = strtoupper($charset[1]);
592  }
593  $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
594  $encodings[] = 'UTF-8';
595  }
596  elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
597  {
598  if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
599  {
600  $encodings[] = $charset[1];
601  }
602  $encodings[] = 'US-ASCII';
603  }
604  // Text MIME-type default
605  elseif (substr($sniffed, 0, 5) === 'text/')
606  {
607  $encodings[] = 'US-ASCII';
608  }
609  }
610  // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
611  $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
612  $encodings[] = 'UTF-8';
613  $encodings[] = 'ISO-8859-1';
614  // There's no point in trying an encoding twice
615  $encodings = array_unique($encodings);
616  // Loop through each possible encoding, till we return something, or run out of possibilities
617  foreach ($encodings as $encoding)
618  {
619  // Change the encoding to UTF-8 (as we always use UTF-8 internally)
620  if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
621  {
622  // Create new parser
623  $parser = $this->registry->create('Parser');
624  // If it's parsed fine
625  if ($parser->parse($utf8_data, 'UTF-8'))
626  {
627  $this->data = $parser->get_data();
628  if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
629  {
630  $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
631  $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
632  return false;
633  }
634  if (isset($headers))
635  {
636  $this->data['headers'] = $headers;
637  }
638  $this->data['build'] = SIMPLEPIE_BUILD;
639  // Cache the file if caching is enabled
640  if ($cache && !$cache->save($this))
641  {
642  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);
643  }
644  return true;
645  }
646  }
647  }
648  if (isset($parser))
649  {
650  // We have an error, just set SimplePie_Misc::error to it and quit
651  $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());
652  }
653  else
654  {
655  $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.';
656  }
657  $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
658  return false;
659  }
660 
661  protected function fetch_data(&$cache)
662  {
663  // If it's enabled, use the cache
664  if ($cache)
665  {
666  // Load the Cache
667  $this->data = $cache->load();
668  if (!empty($this->data))
669  {
670  // If the cache is for an outdated build of SimplePie
671  if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
672  {
673  $cache->unlink();
674  $this->data = array();
675  }
676  // If we've hit a collision just rerun it with caching disabled
677  elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
678  {
679  $cache = false;
680  $this->data = array();
681  }
682  // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
683  elseif (isset($this->data['feed_url']))
684  {
685  // If the autodiscovery cache is still valid use it.
686  if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
687  {
688  // Do not need to do feed autodiscovery yet.
689  if ($this->data['feed_url'] !== $this->data['url'])
690  {
691  $this->set_feed_url($this->data['feed_url']);
692  return $this->init();
693  }
694  $cache->unlink();
695  $this->data = array();
696  }
697  }
698  // Check if the cache has been updated
699  elseif ($cache->mtime() + $this->cache_duration < time())
700  {
701  // If we have last-modified and/or etag set
702  if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
703  {
704  $headers = array(
705  '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',
706  );
707  if (isset($this->data['headers']['last-modified']))
708  {
709  $headers['if-modified-since'] = $this->data['headers']['last-modified'];
710  }
711  if (isset($this->data['headers']['etag']))
712  {
713  $headers['if-none-match'] = $this->data['headers']['etag'];
714  }
715  $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
716  if ($file->success)
717  {
718  if ($file->status_code === 304)
719  {
720  $cache->touch();
721  return true;
722  }
723  }
724  else
725  {
726  unset($file);
727  }
728  }
729  }
730  // If the cache is still valid, just return true
731  else
732  {
733  $this->raw_data = false;
734  return true;
735  }
736  }
737  // If the cache is empty, delete it
738  else
739  {
740  $cache->unlink();
741  $this->data = array();
742  }
743  }
744  // 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.
745  if (!isset($file))
746  {
747  if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
748  {
749  $file =& $this->file;
750  }
751  else
752  {
753  $headers = array(
754  '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',
755  );
756  $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
757  }
758  }
759  // If the file connection has an error, set SimplePie::error to that and quit
760  if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
761  {
762  $this->error = $file->error;
763  return !empty($this->data);
764  }
765  if (!$this->force_feed)
766  {
767  // Check if the supplied URL is a feed, if it isn't, look for it.
768  $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
769  if (!$locate->is_feed($file))
770  {
771  // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
772  unset($file);
773  try
774  {
775  if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
776  {
777  $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.";
778  $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
779  return false;
780  }
781  }
782  catch (SimplePie_Exception $e)
783  {
784  // This is usually because DOMDocument doesn't exist
785  $this->error = $e->getMessage();
786  $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
787  return false;
788  }
789  if ($cache)
790  {
791  $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
792  if (!$cache->save($this))
793  {
794  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);
795  }
796  $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
797  }
798  $this->feed_url = $file->url;
799  }
800  $locate = null;
801  }
802  $this->raw_data = $file->body;
803  $headers = $file->headers;
804  $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
805  $sniffed = $sniffer->get_type();
806  return array($headers, $sniffed);
807  }
808 
809  public function error()
810  {
811  return $this->error;
812  }
813 
814  public function get_raw_data()
815  {
816  return $this->raw_data;
817  }
818 
819  public function get_encoding()
820  {
821  return $this->sanitize->output_encoding;
822  }
823 
824  public function handle_content_type($mime = 'text/html')
825  {
826  if (!headers_sent())
827  {
828  $header = "Content-type: $mime;";
829  if ($this->get_encoding())
830  {
831  $header .= ' charset=' . $this->get_encoding();
832  }
833  else
834  {
835  $header .= ' charset=UTF-8';
836  }
837  header($header);
838  }
839  }
840 
841  public function get_type()
842  {
843  if (!isset($this->data['type']))
844  {
845  $this->data['type'] = SIMPLEPIE_TYPE_ALL;
846  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
847  {
848  $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
849  }
850  elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
851  {
852  $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
853  }
854  elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
855  {
856  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
857  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
858  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
859  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
860  {
861  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
862  }
863  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
864  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
865  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
866  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
867  {
868  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
869  }
870  }
871  elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
872  {
873  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
874  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
875  {
876  switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
877  {
878  case '0.91':
879  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
880  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
881  {
882  switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
883  {
884  case '0':
885  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
886  break;
887  case '24':
888  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
889  break;
890  }
891  }
892  break;
893  case '0.92':
894  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
895  break;
896  case '0.93':
897  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
898  break;
899  case '0.94':
900  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
901  break;
902  case '2.0':
903  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
904  break;
905  }
906  }
907  }
908  else
909  {
910  $this->data['type'] = SIMPLEPIE_TYPE_NONE;
911  }
912  }
913  return $this->data['type'];
914  }
915 
916  public function subscribe_url()
917  {
918  if ($this->feed_url !== null)
919  {
920  return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
921  }
922  else
923  {
924  return null;
925  }
926  }
927 
928  public function get_feed_tags($namespace, $tag)
929  {
930  $type = $this->get_type();
931  if ($type & SIMPLEPIE_TYPE_ATOM_10)
932  {
933  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
934  {
935  return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
936  }
937  }
938  if ($type & SIMPLEPIE_TYPE_ATOM_03)
939  {
940  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
941  {
942  return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
943  }
944  }
945  if ($type & SIMPLEPIE_TYPE_RSS_RDF)
946  {
947  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
948  {
949  return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
950  }
951  }
952  if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
953  {
954  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
955  {
956  return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
957  }
958  }
959  return null;
960  }
961 
962  public function get_channel_tags($namespace, $tag)
963  {
964  $type = $this->get_type();
965  if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
966  {
967  if ($return = $this->get_feed_tags($namespace, $tag))
968  {
969  return $return;
970  }
971  }
972  if ($type & SIMPLEPIE_TYPE_RSS_10)
973  {
974  if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
975  {
976  if (isset($channel[0]['child'][$namespace][$tag]))
977  {
978  return $channel[0]['child'][$namespace][$tag];
979  }
980  }
981  }
982  if ($type & SIMPLEPIE_TYPE_RSS_090)
983  {
984  if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
985  {
986  if (isset($channel[0]['child'][$namespace][$tag]))
987  {
988  return $channel[0]['child'][$namespace][$tag];
989  }
990  }
991  }
992  if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
993  {
994  if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
995  {
996  if (isset($channel[0]['child'][$namespace][$tag]))
997  {
998  return $channel[0]['child'][$namespace][$tag];
999  }
1000  }
1001  }
1002  return null;
1003  }
1004 
1005  public function get_image_tags($namespace, $tag)
1006  {
1007  $type = $this->get_type();
1008  if ($type & SIMPLEPIE_TYPE_RSS_10)
1009  {
1010  if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1011  {
1012  if (isset($image[0]['child'][$namespace][$tag]))
1013  {
1014  return $image[0]['child'][$namespace][$tag];
1015  }
1016  }
1017  }
1018  if ($type & SIMPLEPIE_TYPE_RSS_090)
1019  {
1020  if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1021  {
1022  if (isset($image[0]['child'][$namespace][$tag]))
1023  {
1024  return $image[0]['child'][$namespace][$tag];
1025  }
1026  }
1027  }
1028  if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1029  {
1030  if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
1031  {
1032  if (isset($image[0]['child'][$namespace][$tag]))
1033  {
1034  return $image[0]['child'][$namespace][$tag];
1035  }
1036  }
1037  }
1038  return null;
1039  }
1040 
1041  public function get_base($element = array())
1042  {
1043  if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
1044  {
1045  return $element['xml_base'];
1046  }
1047  elseif ($this->get_link() !== null)
1048  {
1049  return $this->get_link();
1050  }
1051  else
1052  {
1053  return $this->subscribe_url();
1054  }
1055  }
1056 
1057  public function sanitize($data, $type, $base = '')
1058  {
1059  return $this->sanitize->sanitize($data, $type, $base);
1060  }
1061 
1062  public function get_title()
1063  {
1064  if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
1065  {
1066  return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1067  }
1068  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
1069  {
1070  return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1071  }
1072  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1073  {
1074  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1075  }
1076  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1077  {
1078  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1079  }
1080  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
1081  {
1082  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1083  }
1084  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
1085  {
1086  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1087  }
1088  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
1089  {
1090  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1091  }
1092  else
1093  {
1094  return null;
1095  }
1096  }
1097 
1098  public function get_category($key = 0)
1099  {
1100  $categories = $this->get_categories();
1101  if (isset($categories[$key]))
1102  {
1103  return $categories[$key];
1104  }
1105  else
1106  {
1107  return null;
1108  }
1109  }
1110 
1111  public function get_categories()
1112  {
1113  $categories = array();
1114  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
1115  {
1116  $term = null;
1117  $scheme = null;
1118  $label = null;
1119  if (isset($category['attribs']['']['term']))
1120  {
1121  $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
1122  }
1123  if (isset($category['attribs']['']['scheme']))
1124  {
1125  $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1126  }
1127  if (isset($category['attribs']['']['label']))
1128  {
1129  $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
1130  }
1131  $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
1132  }
1133  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
1134  {
1135  // This is really the label, but keep this as the term also for BC.
1136  // Label will also work on retrieving because that falls back to term.
1137  $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1138  if (isset($category['attribs']['']['domain']))
1139  {
1140  $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
1141  }
1142  else
1143  {
1144  $scheme = null;
1145  }
1146  $categories[] = $this->registry->create('Category', array($term, $scheme, null));
1147  }
1148  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
1149  {
1150  $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
1151  }
1152  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
1153  {
1154  $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
1155  }
1156  if (!empty($categories))
1157  {
1158  return array_unique($categories);
1159  }
1160  else
1161  {
1162  return null;
1163  }
1164  }
1165 
1166  public function get_author($key = 0)
1167  {
1168  $authors = $this->get_authors();
1169  if (isset($authors[$key]))
1170  {
1171  return $authors[$key];
1172  }
1173  else
1174  {
1175  return null;
1176  }
1177  }
1178 
1179  public function get_authors()
1180  {
1181  $authors = array();
1182  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
1183  {
1184  $name = null;
1185  $uri = null;
1186  $email = null;
1187  if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
1188  {
1189  $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1190  }
1191  if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
1192  {
1193  $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]));
1194  }
1195  if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
1196  {
1197  $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1198  }
1199  if ($name !== null || $email !== null || $uri !== null)
1200  {
1201  $authors[] = $this->registry->create('Author', array($name, $uri, $email));
1202  }
1203  }
1204  if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
1205  {
1206  $name = null;
1207  $url = null;
1208  $email = null;
1209  if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
1210  {
1211  $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1212  }
1213  if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
1214  {
1215  $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]));
1216  }
1217  if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
1218  {
1219  $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1220  }
1221  if ($name !== null || $email !== null || $url !== null)
1222  {
1223  $authors[] = $this->registry->create('Author', array($name, $url, $email));
1224  }
1225  }
1226  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
1227  {
1228  $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
1229  }
1230  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
1231  {
1232  $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
1233  }
1234  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
1235  {
1236  $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
1237  }
1238  if (!empty($authors))
1239  {
1240  return array_unique($authors);
1241  }
1242  else
1243  {
1244  return null;
1245  }
1246  }
1247 
1248  public function get_contributor($key = 0)
1249  {
1250  $contributors = $this->get_contributors();
1251  if (isset($contributors[$key]))
1252  {
1253  return $contributors[$key];
1254  }
1255  else
1256  {
1257  return null;
1258  }
1259  }
1260 
1261  public function get_contributors()
1262  {
1263  $contributors = array();
1264  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
1265  {
1266  $name = null;
1267  $uri = null;
1268  $email = null;
1269  if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
1270  {
1271  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1272  }
1273  if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
1274  {
1275  $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]));
1276  }
1277  if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
1278  {
1279  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1280  }
1281  if ($name !== null || $email !== null || $uri !== null)
1282  {
1283  $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
1284  }
1285  }
1286  foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
1287  {
1288  $name = null;
1289  $url = null;
1290  $email = null;
1291  if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
1292  {
1293  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1294  }
1295  if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
1296  {
1297  $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]));
1298  }
1299  if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
1300  {
1301  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1302  }
1303  if ($name !== null || $email !== null || $url !== null)
1304  {
1305  $contributors[] = $this->registry->create('Author', array($name, $url, $email));
1306  }
1307  }
1308  if (!empty($contributors))
1309  {
1310  return array_unique($contributors);
1311  }
1312  else
1313  {
1314  return null;
1315  }
1316  }
1317 
1318  public function get_link($key = 0, $rel = 'alternate')
1319  {
1320  $links = $this->get_links($rel);
1321  if (isset($links[$key]))
1322  {
1323  return $links[$key];
1324  }
1325  else
1326  {
1327  return null;
1328  }
1329  }
1330 
1331  public function get_permalink()
1332  {
1333  return $this->get_link(0);
1334  }
1335 
1336  public function get_links($rel = 'alternate')
1337  {
1338  if (!isset($this->data['links']))
1339  {
1340  $this->data['links'] = array();
1341  if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
1342  {
1343  foreach ($links as $link)
1344  {
1345  if (isset($link['attribs']['']['href']))
1346  {
1347  $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
1348  $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
1349  }
1350  }
1351  }
1352  if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
1353  {
1354  foreach ($links as $link)
1355  {
1356  if (isset($link['attribs']['']['href']))
1357  {
1358  $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
1359  $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
1360  }
1361  }
1362  }
1363  if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
1364  {
1365  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
1366  }
1367  if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
1368  {
1369  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
1370  }
1371  if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
1372  {
1373  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
1374  }
1375  $keys = array_keys($this->data['links']);
1376  foreach ($keys as $key)
1377  {
1378  if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
1379  {
1380  if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
1381  {
1382  $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
1383  $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
1384  }
1385  else
1386  {
1387  $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
1388  }
1389  }
1390  elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
1391  {
1392  $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
1393  }
1394  $this->data['links'][$key] = array_unique($this->data['links'][$key]);
1395  }
1396  }
1397  if (isset($this->data['links'][$rel]))
1398  {
1399  return $this->data['links'][$rel];
1400  }
1401  else
1402  {
1403  return null;
1404  }
1405  }
1406  public function get_all_discovered_feeds()
1407  {
1409  }
1410 
1411  public function get_description()
1412  {
1413  if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
1414  {
1415  return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1416  }
1417  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
1418  {
1419  return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1420  }
1421  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
1422  {
1423  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1424  }
1425  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
1426  {
1427  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1428  }
1429  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
1430  {
1431  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
1432  }
1433  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
1434  {
1435  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1436  }
1437  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
1438  {
1439  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1440  }
1441  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
1442  {
1443  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
1444  }
1445  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
1446  {
1447  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
1448  }
1449  else
1450  {
1451  return null;
1452  }
1453  }
1454 
1455  public function get_copyright()
1456  {
1457  if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
1458  {
1459  return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1460  }
1461  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
1462  {
1463  return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1464  }
1465  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
1466  {
1467  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1468  }
1469  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
1470  {
1471  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1472  }
1473  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
1474  {
1475  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1476  }
1477  else
1478  {
1479  return null;
1480  }
1481  }
1482 
1483  public function get_language()
1484  {
1485  if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
1486  {
1487  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1488  }
1489  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
1490  {
1491  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1492  }
1493  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
1494  {
1495  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1496  }
1497  elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
1498  {
1499  return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1500  }
1501  elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
1502  {
1503  return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1504  }
1505  elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
1506  {
1507  return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1508  }
1509  elseif (isset($this->data['headers']['content-language']))
1510  {
1511  return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
1512  }
1513  else
1514  {
1515  return null;
1516  }
1517  }
1518 
1519  public function get_latitude()
1520  {
1521  if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
1522  {
1523  return (float) $return[0]['data'];
1524  }
1525  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))
1526  {
1527  return (float) $match[1];
1528  }
1529  else
1530  {
1531  return null;
1532  }
1533  }
1534 
1535  public function get_longitude()
1536  {
1537  if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
1538  {
1539  return (float) $return[0]['data'];
1540  }
1541  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
1542  {
1543  return (float) $return[0]['data'];
1544  }
1545  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))
1546  {
1547  return (float) $match[2];
1548  }
1549  else
1550  {
1551  return null;
1552  }
1553  }
1554 
1555  public function get_image_title()
1556  {
1557  if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1558  {
1559  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1560  }
1561  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1562  {
1563  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1564  }
1565  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
1566  {
1567  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1568  }
1569  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
1570  {
1571  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1572  }
1573  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
1574  {
1575  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1576  }
1577  else
1578  {
1579  return null;
1580  }
1581  }
1582 
1583  public function get_image_url()
1584  {
1585  if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
1586  {
1587  return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
1588  }
1589  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
1590  {
1591  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1592  }
1593  elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
1594  {
1595  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1596  }
1597  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
1598  {
1599  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1600  }
1601  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
1602  {
1603  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1604  }
1605  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
1606  {
1607  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1608  }
1609  else
1610  {
1611  return null;
1612  }
1613  }
1614 
1615  public function get_image_link()
1616  {
1617  if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
1618  {
1619  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1620  }
1621  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
1622  {
1623  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1624  }
1625  elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
1626  {
1627  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1628  }
1629  else
1630  {
1631  return null;
1632  }
1633  }
1634 
1635  public function get_image_width()
1636  {
1637  if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
1638  {
1639  return round($return[0]['data']);
1640  }
1642  {
1643  return 88.0;
1644  }
1645  else
1646  {
1647  return null;
1648  }
1649  }
1650 
1651  public function get_image_height()
1652  {
1653  if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
1654  {
1655  return round($return[0]['data']);
1656  }
1658  {
1659  return 31.0;
1660  }
1661  else
1662  {
1663  return null;
1664  }
1665  }
1666 
1667  public function get_item_quantity($max = 0)
1668  {
1669  $max = (int) $max;
1670  $qty = count($this->get_items());
1671  if ($max === 0)
1672  {
1673  return $qty;
1674  }
1675  else
1676  {
1677  return ($qty > $max) ? $max : $qty;
1678  }
1679  }
1680 
1681  public function get_item($key = 0)
1682  {
1683  $items = $this->get_items();
1684  if (isset($items[$key]))
1685  {
1686  return $items[$key];
1687  }
1688  else
1689  {
1690  return null;
1691  }
1692  }
1693 
1694  public function get_items($start = 0, $end = 0)
1695  {
1696  if (!isset($this->data['items']))
1697  {
1698  if (!empty($this->multifeed_objects))
1699  {
1700  $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
1701  }
1702  else
1703  {
1704  $this->data['items'] = array();
1705  if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
1706  {
1707  $keys = array_keys($items);
1708  foreach ($keys as $key)
1709  {
1710  $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
1711  }
1712  }
1713  if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
1714  {
1715  $keys = array_keys($items);
1716  foreach ($keys as $key)
1717  {
1718  $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
1719  }
1720  }
1721  if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
1722  {
1723  $keys = array_keys($items);
1724  foreach ($keys as $key)
1725  {
1726  $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
1727  }
1728  }
1729  if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
1730  {
1731  $keys = array_keys($items);
1732  foreach ($keys as $key)
1733  {
1734  $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
1735  }
1736  }
1737  if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
1738  {
1739  $keys = array_keys($items);
1740  foreach ($keys as $key)
1741  {
1742  $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
1743  }
1744  }
1745  }
1746  }
1747  if (!empty($this->data['items']))
1748  {
1749  // If we want to order it by date, check if all items have a date, and then sort it
1750  if ($this->order_by_date && empty($this->multifeed_objects))
1751  {
1752  if (!isset($this->data['ordered_items']))
1753  {
1754  $do_sort = true;
1755  foreach ($this->data['items'] as $item)
1756  {
1757  if (!$item->get_date('U'))
1758  {
1759  $do_sort = false;
1760  break;
1761  }
1762  }
1763  $item = null;
1764  $this->data['ordered_items'] = $this->data['items'];
1765  if ($do_sort)
1766  {
1767  usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
1768  }
1769  }
1770  $items = $this->data['ordered_items'];
1771  }
1772  else
1773  {
1774  $items = $this->data['items'];
1775  }
1776  // Slice the data as desired
1777  if ($end === 0)
1778  {
1779  return array_slice($items, $start);
1780  }
1781  else
1782  {
1783  return array_slice($items, $start, $end);
1784  }
1785  }
1786  else
1787  {
1788  return array();
1789  }
1790  }
1791 
1792  public function set_favicon_handler($page = false, $qs = 'i')
1793  {
1794  $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
1795  trigger_error('Favicon handling has been removed, please use your own handling', $level);
1796  return false;
1797  }
1798 
1799  public function get_favicon()
1800  {
1801  $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
1802  trigger_error('Favicon handling has been removed, please use your own handling', $level);
1803  if (($url = $this->get_link()) !== null)
1804  {
1805  return 'http://g.etfv.co/' . urlencode($url);
1806  }
1807  return false;
1808  }
1809 
1810  public function __call($method, $args)
1811  {
1812  if (strpos($method, 'subscribe_') === 0)
1813  {
1814  $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
1815  trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
1816  return '';
1817  }
1818  if ($method === 'enable_xml_dump')
1819  {
1820  $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
1821  trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
1822  return false;
1823  }
1824  $class = get_class($this);
1825  $trace = debug_backtrace();
1826  $file = $trace[0]['file'];
1827  $line = $trace[0]['line'];
1828  trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
1829  }
1830 
1831  public static function sort_items($a, $b)
1832  {
1833  return $a->get_date('U') <= $b->get_date('U');
1834  }
1835 
1836  public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
1837  {
1838  if (is_array($urls) && sizeof($urls) > 0)
1839  {
1840  $items = array();
1841  foreach ($urls as $arg)
1842  {
1843  if ($arg instanceof SimplePie)
1844  {
1845  $items = array_merge($items, $arg->get_items(0, $limit));
1846  }
1847  else
1848  {
1849  trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
1850  }
1851  }
1852  $do_sort = true;
1853  foreach ($items as $item)
1854  {
1855  if (!$item->get_date('U'))
1856  {
1857  $do_sort = false;
1858  break;
1859  }
1860  }
1861  $item = null;
1862  if ($do_sort)
1863  {
1864  usort($items, array(get_class($urls[0]), 'sort_items'));
1865  }
1866  if ($end === 0)
1867  {
1868  return array_slice($items, $start);
1869  }
1870  else
1871  {
1872  return array_slice($items, $start, $end);
1873  }
1874  }
1875  else
1876  {
1877  trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
1878  return array();
1879  }
1880  }
1881 }
1883 {
1884 
1885  var $name;
1886 
1887  var $link;
1888 
1889  var $email;
1890 
1891  public function __construct($name = null, $link = null, $email = null)
1892  {
1893  $this->name = $name;
1894  $this->link = $link;
1895  $this->email = $email;
1896  }
1897 
1898  public function __toString()
1899  {
1900  // There is no $this->data here
1901  return md5(serialize($this));
1902  }
1903 
1904  public function get_name()
1905  {
1906  if ($this->name !== null)
1907  {
1908  return $this->name;
1909  }
1910  else
1911  {
1912  return null;
1913  }
1914  }
1915 
1916  public function get_link()
1917  {
1918  if ($this->link !== null)
1919  {
1920  return $this->link;
1921  }
1922  else
1923  {
1924  return null;
1925  }
1926  }
1927 
1928  public function get_email()
1929  {
1930  if ($this->email !== null)
1931  {
1932  return $this->email;
1933  }
1934  else
1935  {
1936  return null;
1937  }
1938  }
1939 }
1941 {
1942 
1943  const TYPE_FEED = 'spc';
1944 
1945  const TYPE_IMAGE = 'spi';
1946 
1947  public function __construct($location, $name, $type);
1948 
1949  public function save($data);
1950 
1951  public function load();
1952 
1953  public function mtime();
1954 
1955  public function touch();
1956 
1957  public function unlink();
1958 }
1959 abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
1960 {
1961 
1962  protected static function prepare_simplepie_object_for_cache($data)
1963  {
1964  $items = $data->get_items();
1965  $items_by_id = array();
1966  if (!empty($items))
1967  {
1968  foreach ($items as $item)
1969  {
1970  $items_by_id[$item->get_id()] = $item;
1971  }
1972  if (count($items_by_id) !== count($items))
1973  {
1974  $items_by_id = array();
1975  foreach ($items as $item)
1976  {
1977  $items_by_id[$item->get_id(true)] = $item;
1978  }
1979  }
1980  if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
1981  {
1982  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
1983  }
1984  elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
1985  {
1986  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
1987  }
1988  elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
1989  {
1990  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
1991  }
1992  elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
1993  {
1994  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
1995  }
1996  else
1997  {
1998  $channel = null;
1999  }
2000  if ($channel !== null)
2001  {
2002  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
2003  {
2004  unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
2005  }
2006  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
2007  {
2008  unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
2009  }
2010  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
2011  {
2012  unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
2013  }
2014  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
2015  {
2016  unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
2017  }
2018  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
2019  {
2020  unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
2021  }
2022  }
2023  if (isset($data->data['items']))
2024  {
2025  unset($data->data['items']);
2026  }
2027  if (isset($data->data['ordered_items']))
2028  {
2029  unset($data->data['ordered_items']);
2030  }
2031  }
2032  return array(serialize($data->data), $items_by_id);
2033  }
2034 }
2036 {
2037 
2038  protected $location;
2039 
2040  protected $filename;
2041 
2042  protected $extension;
2043 
2044  protected $name;
2045 
2046  public function __construct($location, $name, $type)
2047  {
2048  $this->location = $location;
2049  $this->filename = $name;
2050  $this->extension = $type;
2051  $this->name = "$this->location/$this->filename.$this->extension";
2052  }
2053 
2054  public function save($data)
2055  {
2056  if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
2057  {
2058  if ($data instanceof SimplePie)
2059  {
2060  $data = $data->data;
2061  }
2062  $data = serialize($data);
2063  return (bool) file_put_contents($this->name, $data);
2064  }
2065  return false;
2066  }
2067 
2068  public function load()
2069  {
2070  if (file_exists($this->name) && is_readable($this->name))
2071  {
2072  return unserialize(file_get_contents($this->name));
2073  }
2074  return false;
2075  }
2076 
2077  public function mtime()
2078  {
2079  if (file_exists($this->name))
2080  {
2081  return filemtime($this->name);
2082  }
2083  return false;
2084  }
2085 
2086  public function touch()
2087  {
2088  if (file_exists($this->name))
2089  {
2090  return touch($this->name);
2091  }
2092  return false;
2093  }
2094 
2095  public function unlink()
2096  {
2097  if (file_exists($this->name))
2098  {
2099  return unlink($this->name);
2100  }
2101  return false;
2102  }
2103 }
2105 {
2106 
2107  protected $cache;
2108 
2109  protected $options;
2110 
2111  protected $name;
2112 
2113  public function __construct($location, $name, $type)
2114  {
2115  $this->options = array(
2116  'host' => '127.0.0.1',
2117  'port' => 11211,
2118  'extras' => array(
2119  'timeout' => 3600, // one hour
2120  'prefix' => 'simplepie_',
2121  ),
2122  );
2123  $parsed = SimplePie_Cache::parse_URL($location);
2124  $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
2125  $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
2126  $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
2127  $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
2128  $this->cache = new Memcache();
2129  $this->cache->addServer($this->options['host'], (int) $this->options['port']);
2130  }
2131 
2132  public function save($data)
2133  {
2134  if ($data instanceof SimplePie)
2135  {
2136  $data = $data->data;
2137  }
2138  return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
2139  }
2140 
2141  public function load()
2142  {
2143  $data = $this->cache->get($this->name);
2144  if ($data !== false)
2145  {
2146  return unserialize($data);
2147  }
2148  return false;
2149  }
2150 
2151  public function mtime()
2152  {
2153  $data = $this->cache->get($this->name);
2154  if ($data !== false)
2155  {
2156  // essentially ignore the mtime because Memcache expires on it's own
2157  return time();
2158  }
2159  return false;
2160  }
2161 
2162  public function touch()
2163  {
2164  $data = $this->cache->get($this->name);
2165  if ($data !== false)
2166  {
2167  return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
2168  }
2169  return false;
2170  }
2171 
2172  public function unlink()
2173  {
2174  return $this->cache->delete($this->name, 0);
2175  }
2176 }
2178 {
2179 
2180  protected $mysql;
2181 
2182  protected $options;
2183 
2184  protected $id;
2185 
2186  public function __construct($location, $name, $type)
2187  {
2188  $this->options = array(
2189  'user' => null,
2190  'pass' => null,
2191  'host' => '127.0.0.1',
2192  'port' => '3306',
2193  'path' => '',
2194  'extras' => array(
2195  'prefix' => '',
2196  ),
2197  );
2198  $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
2199  // Path is prefixed with a "/"
2200  $this->options['dbname'] = substr($this->options['path'], 1);
2201  try
2202  {
2203  $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'));
2204  }
2205  catch (PDOException $e)
2206  {
2207  $this->mysql = null;
2208  return;
2209  }
2210  $this->id = $name . $type;
2211  if (!$query = $this->mysql->query('SHOW TABLES'))
2212  {
2213  $this->mysql = null;
2214  return;
2215  }
2216  $db = array();
2217  while ($row = $query->fetchColumn())
2218  {
2219  $db[] = $row;
2220  }
2221  if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
2222  {
2223  $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)))');
2224  if ($query === false)
2225  {
2226  $this->mysql = null;
2227  }
2228  }
2229  if (!in_array($this->options['extras']['prefix'] . 'items', $db))
2230  {
2231  $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)))');
2232  if ($query === false)
2233  {
2234  $this->mysql = null;
2235  }
2236  }
2237  }
2238 
2239  public function save($data)
2240  {
2241  if ($this->mysql === null)
2242  {
2243  return false;
2244  }
2245  if ($data instanceof SimplePie)
2246  {
2247  $data = clone $data;
2248  $prepared = self::prepare_simplepie_object_for_cache($data);
2249  $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
2250  $query->bindValue(':feed', $this->id);
2251  if ($query->execute())
2252  {
2253  if ($query->fetchColumn() > 0)
2254  {
2255  $items = count($prepared[1]);
2256  if ($items)
2257  {
2258  $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
2259  $query = $this->mysql->prepare($sql);
2260  $query->bindValue(':items', $items);
2261  }
2262  else
2263  {
2264  $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
2265  $query = $this->mysql->prepare($sql);
2266  }
2267  $query->bindValue(':data', $prepared[0]);
2268  $query->bindValue(':time', time());
2269  $query->bindValue(':feed', $this->id);
2270  if (!$query->execute())
2271  {
2272  return false;
2273  }
2274  }
2275  else
2276  {
2277  $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
2278  $query->bindValue(':feed', $this->id);
2279  $query->bindValue(':count', count($prepared[1]));
2280  $query->bindValue(':data', $prepared[0]);
2281  $query->bindValue(':time', time());
2282  if (!$query->execute())
2283  {
2284  return false;
2285  }
2286  }
2287  $ids = array_keys($prepared[1]);
2288  if (!empty($ids))
2289  {
2290  foreach ($ids as $id)
2291  {
2292  $database_ids[] = $this->mysql->quote($id);
2293  }
2294  $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
2295  $query->bindValue(':feed', $this->id);
2296  if ($query->execute())
2297  {
2298  $existing_ids = array();
2299  while ($row = $query->fetchColumn())
2300  {
2301  $existing_ids[] = $row;
2302  }
2303  $new_ids = array_diff($ids, $existing_ids);
2304  foreach ($new_ids as $new_id)
2305  {
2306  if (!($date = $prepared[1][$new_id]->get_date('U')))
2307  {
2308  $date = time();
2309  }
2310  $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
2311  $query->bindValue(':feed', $this->id);
2312  $query->bindValue(':id', $new_id);
2313  $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
2314  $query->bindValue(':date', $date);
2315  if (!$query->execute())
2316  {
2317  return false;
2318  }
2319  }
2320  return true;
2321  }
2322  }
2323  else
2324  {
2325  return true;
2326  }
2327  }
2328  }
2329  else
2330  {
2331  $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
2332  $query->bindValue(':feed', $this->id);
2333  if ($query->execute())
2334  {
2335  if ($query->rowCount() > 0)
2336  {
2337  $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
2338  $query->bindValue(':data', serialize($data));
2339  $query->bindValue(':time', time());
2340  $query->bindValue(':feed', $this->id);
2341  if ($this->execute())
2342  {
2343  return true;
2344  }
2345  }
2346  else
2347  {
2348  $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
2349  $query->bindValue(':id', $this->id);
2350  $query->bindValue(':data', serialize($data));
2351  $query->bindValue(':time', time());
2352  if ($query->execute())
2353  {
2354  return true;
2355  }
2356  }
2357  }
2358  }
2359  return false;
2360  }
2361 
2362  public function load()
2363  {
2364  if ($this->mysql === null)
2365  {
2366  return false;
2367  }
2368  $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
2369  $query->bindValue(':id', $this->id);
2370  if ($query->execute() && ($row = $query->fetch()))
2371  {
2372  $data = unserialize($row[1]);
2373  if (isset($this->options['items'][0]))
2374  {
2375  $items = (int) $this->options['items'][0];
2376  }
2377  else
2378  {
2379  $items = (int) $row[0];
2380  }
2381  if ($items !== 0)
2382  {
2383  if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
2384  {
2385  $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
2386  }
2387  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
2388  {
2389  $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
2390  }
2391  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
2392  {
2393  $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
2394  }
2395  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
2396  {
2397  $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
2398  }
2399  else
2400  {
2401  $feed = null;
2402  }
2403  if ($feed !== null)
2404  {
2405  $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
2406  if ($items > 0)
2407  {
2408  $sql .= ' LIMIT ' . $items;
2409  }
2410  $query = $this->mysql->prepare($sql);
2411  $query->bindValue(':feed', $this->id);
2412  if ($query->execute())
2413  {
2414  while ($row = $query->fetchColumn())
2415  {
2416  $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
2417  }
2418  }
2419  else
2420  {
2421  return false;
2422  }
2423  }
2424  }
2425  return $data;
2426  }
2427  return false;
2428  }
2429 
2430  public function mtime()
2431  {
2432  if ($this->mysql === null)
2433  {
2434  return false;
2435  }
2436  $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
2437  $query->bindValue(':id', $this->id);
2438  if ($query->execute() && ($time = $query->fetchColumn()))
2439  {
2440  return $time;
2441  }
2442  else
2443  {
2444  return false;
2445  }
2446  }
2447 
2448  public function touch()
2449  {
2450  if ($this->mysql === null)
2451  {
2452  return false;
2453  }
2454  $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
2455  $query->bindValue(':time', time());
2456  $query->bindValue(':id', $this->id);
2457  if ($query->execute() && $query->rowCount() > 0)
2458  {
2459  return true;
2460  }
2461  else
2462  {
2463  return false;
2464  }
2465  }
2466 
2467  public function unlink()
2468  {
2469  if ($this->mysql === null)
2470  {
2471  return false;
2472  }
2473  $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
2474  $query->bindValue(':id', $this->id);
2475  $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
2476  $query2->bindValue(':id', $this->id);
2477  if ($query->execute() && $query2->execute())
2478  {
2479  return true;
2480  }
2481  else
2482  {
2483  return false;
2484  }
2485  }
2486 }
2488 {
2489 
2490  protected static $handlers = array(
2491  'mysql' => 'SimplePie_Cache_MySQL',
2492  'memcache' => 'SimplePie_Cache_Memcache',
2493  );
2494 
2495  private function __construct() { }
2496 
2497  public static function get_handler($location, $filename, $extension)
2498  {
2499  $type = explode(':', $location, 2);
2500  $type = $type[0];
2501  if (!empty(self::$handlers[$type]))
2502  {
2503  $class = self::$handlers[$type];
2504  return new $class($location, $filename, $extension);
2505  }
2506  return new SimplePie_Cache_File($location, $filename, $extension);
2507  }
2508 
2509  public function create($location, $filename, $extension)
2510  {
2511  trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
2512  return self::get_handler($location, $filename, $extension);
2513  }
2514 
2515  public static function register($type, $class)
2516  {
2517  self::$handlers[$type] = $class;
2518  }
2519 
2520  public static function parse_URL($url)
2521  {
2522  $params = parse_url($url);
2523  $params['extras'] = array();
2524  if (isset($params['query']))
2525  {
2526  parse_str($params['query'], $params['extras']);
2527  }
2528  return $params;
2529  }
2530 }
2532 {
2533 
2534  var $type;
2535 
2536  var $lang;
2537 
2539 
2541 
2542  var $text;
2543 
2544  public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
2545  {
2546  $this->type = $type;
2547  $this->lang = $lang;
2548  $this->startTime = $startTime;
2549  $this->endTime = $endTime;
2550  $this->text = $text;
2551  }
2552 
2553  public function __toString()
2554  {
2555  // There is no $this->data here
2556  return md5(serialize($this));
2557  }
2558 
2559  public function get_endtime()
2560  {
2561  if ($this->endTime !== null)
2562  {
2563  return $this->endTime;
2564  }
2565  else
2566  {
2567  return null;
2568  }
2569  }
2570 
2571  public function get_language()
2572  {
2573  if ($this->lang !== null)
2574  {
2575  return $this->lang;
2576  }
2577  else
2578  {
2579  return null;
2580  }
2581  }
2582 
2583  public function get_starttime()
2584  {
2585  if ($this->startTime !== null)
2586  {
2587  return $this->startTime;
2588  }
2589  else
2590  {
2591  return null;
2592  }
2593  }
2594 
2595  public function get_text()
2596  {
2597  if ($this->text !== null)
2598  {
2599  return $this->text;
2600  }
2601  else
2602  {
2603  return null;
2604  }
2605  }
2606 
2607  public function get_type()
2608  {
2609  if ($this->type !== null)
2610  {
2611  return $this->type;
2612  }
2613  else
2614  {
2615  return null;
2616  }
2617  }
2618 }
2620 {
2621 
2622  var $term;
2623 
2624  var $scheme;
2625 
2626  var $label;
2627 
2628  public function __construct($term = null, $scheme = null, $label = null)
2629  {
2630  $this->term = $term;
2631  $this->scheme = $scheme;
2632  $this->label = $label;
2633  }
2634 
2635  public function __toString()
2636  {
2637  // There is no $this->data here
2638  return md5(serialize($this));
2639  }
2640 
2641  public function get_term()
2642  {
2643  if ($this->term !== null)
2644  {
2645  return $this->term;
2646  }
2647  else
2648  {
2649  return null;
2650  }
2651  }
2652 
2653  public function get_scheme()
2654  {
2655  if ($this->scheme !== null)
2656  {
2657  return $this->scheme;
2658  }
2659  else
2660  {
2661  return null;
2662  }
2663  }
2664 
2665  public function get_label()
2666  {
2667  if ($this->label !== null)
2668  {
2669  return $this->label;
2670  }
2671  else
2672  {
2673  return $this->get_term();
2674  }
2675  }
2676 }
2678 {
2679 
2680  var $file;
2681 
2682  public function __construct($file)
2683  {
2684  $this->file = $file;
2685  }
2686 
2687  public function get_type()
2688  {
2689  if (isset($this->file->headers['content-type']))
2690  {
2691  if (!isset($this->file->headers['content-encoding'])
2692  && ($this->file->headers['content-type'] === 'text/plain'
2693  || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
2694  || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
2695  || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
2696  {
2697  return $this->text_or_binary();
2698  }
2699  if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
2700  {
2701  $official = substr($this->file->headers['content-type'], 0, $pos);
2702  }
2703  else
2704  {
2705  $official = $this->file->headers['content-type'];
2706  }
2707  $official = trim(strtolower($official));
2708  if ($official === 'unknown/unknown'
2709  || $official === 'application/unknown')
2710  {
2711  return $this->unknown();
2712  }
2713  elseif (substr($official, -4) === '+xml'
2714  || $official === 'text/xml'
2715  || $official === 'application/xml')
2716  {
2717  return $official;
2718  }
2719  elseif (substr($official, 0, 6) === 'image/')
2720  {
2721  if ($return = $this->image())
2722  {
2723  return $return;
2724  }
2725  else
2726  {
2727  return $official;
2728  }
2729  }
2730  elseif ($official === 'text/html')
2731  {
2732  return $this->feed_or_html();
2733  }
2734  else
2735  {
2736  return $official;
2737  }
2738  }
2739  else
2740  {
2741  return $this->unknown();
2742  }
2743  }
2744 
2745  public function text_or_binary()
2746  {
2747  if (substr($this->file->body, 0, 2) === "\xFE\xFF"
2748  || substr($this->file->body, 0, 2) === "\xFF\xFE"
2749  || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
2750  || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
2751  {
2752  return 'text/plain';
2753  }
2754  elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
2755  {
2756  return 'application/octect-stream';
2757  }
2758  else
2759  {
2760  return 'text/plain';
2761  }
2762  }
2763 
2764  public function unknown()
2765  {
2766  $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
2767  if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
2768  || strtolower(substr($this->file->body, $ws, 5)) === '<html'
2769  || strtolower(substr($this->file->body, $ws, 7)) === '<script')
2770  {
2771  return 'text/html';
2772  }
2773  elseif (substr($this->file->body, 0, 5) === '%PDF-')
2774  {
2775  return 'application/pdf';
2776  }
2777  elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
2778  {
2779  return 'application/postscript';
2780  }
2781  elseif (substr($this->file->body, 0, 6) === 'GIF87a'
2782  || substr($this->file->body, 0, 6) === 'GIF89a')
2783  {
2784  return 'image/gif';
2785  }
2786  elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
2787  {
2788  return 'image/png';
2789  }
2790  elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
2791  {
2792  return 'image/jpeg';
2793  }
2794  elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
2795  {
2796  return 'image/bmp';
2797  }
2798  elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
2799  {
2800  return 'image/vnd.microsoft.icon';
2801  }
2802  else
2803  {
2804  return $this->text_or_binary();
2805  }
2806  }
2807 
2808  public function image()
2809  {
2810  if (substr($this->file->body, 0, 6) === 'GIF87a'
2811  || substr($this->file->body, 0, 6) === 'GIF89a')
2812  {
2813  return 'image/gif';
2814  }
2815  elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
2816  {
2817  return 'image/png';
2818  }
2819  elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
2820  {
2821  return 'image/jpeg';
2822  }
2823  elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
2824  {
2825  return 'image/bmp';
2826  }
2827  elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
2828  {
2829  return 'image/vnd.microsoft.icon';
2830  }
2831  else
2832  {
2833  return false;
2834  }
2835  }
2836 
2837  public function feed_or_html()
2838  {
2839  $len = strlen($this->file->body);
2840  $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
2841  while ($pos < $len)
2842  {
2843  switch ($this->file->body[$pos])
2844  {
2845  case "\x09":
2846  case "\x0A":
2847  case "\x0D":
2848  case "\x20":
2849  $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
2850  continue 2;
2851  case '<':
2852  $pos++;
2853  break;
2854  default:
2855  return 'text/html';
2856  }
2857  if (substr($this->file->body, $pos, 3) === '!--')
2858  {
2859  $pos += 3;
2860  if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
2861  {
2862  $pos += 3;
2863  }
2864  else
2865  {
2866  return 'text/html';
2867  }
2868  }
2869  elseif (substr($this->file->body, $pos, 1) === '!')
2870  {
2871  if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
2872  {
2873  $pos++;
2874  }
2875  else
2876  {
2877  return 'text/html';
2878  }
2879  }
2880  elseif (substr($this->file->body, $pos, 1) === '?')
2881  {
2882  if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
2883  {
2884  $pos += 2;
2885  }
2886  else
2887  {
2888  return 'text/html';
2889  }
2890  }
2891  elseif (substr($this->file->body, $pos, 3) === 'rss'
2892  || substr($this->file->body, $pos, 7) === 'rdf:RDF')
2893  {
2894  return 'application/rss+xml';
2895  }
2896  elseif (substr($this->file->body, $pos, 4) === 'feed')
2897  {
2898  return 'application/atom+xml';
2899  }
2900  else
2901  {
2902  return 'text/html';
2903  }
2904  }
2905  return 'text/html';
2906  }
2907 }
2909 {
2910 
2911  var $url;
2912 
2913  var $label;
2914 
2915  public function __construct($url = null, $label = null)
2916  {
2917  $this->url = $url;
2918  $this->label = $label;
2919  }
2920 
2921  public function __toString()
2922  {
2923  // There is no $this->data here
2924  return md5(serialize($this));
2925  }
2926 
2927  public function get_url()
2928  {
2929  if ($this->url !== null)
2930  {
2931  return $this->url;
2932  }
2933  else
2934  {
2935  return null;
2936  }
2937  }
2938 
2939  public function get_attribution()
2940  {
2941  if ($this->label !== null)
2942  {
2943  return $this->label;
2944  }
2945  else
2946  {
2947  return null;
2948  }
2949  }
2950 }
2952 {
2953 }
2955 {
2956 
2957  var $role;
2958 
2959  var $scheme;
2960 
2961  var $name;
2962 
2963  public function __construct($role = null, $scheme = null, $name = null)
2964  {
2965  $this->role = $role;
2966  $this->scheme = $scheme;
2967  $this->name = $name;
2968  }
2969 
2970  public function __toString()
2971  {
2972  // There is no $this->data here
2973  return md5(serialize($this));
2974  }
2975 
2976  public function get_role()
2977  {
2978  if ($this->role !== null)
2979  {
2980  return $this->role;
2981  }
2982  else
2983  {
2984  return null;
2985  }
2986  }
2987 
2988  public function get_scheme()
2989  {
2990  if ($this->scheme !== null)
2991  {
2992  return $this->scheme;
2993  }
2994  else
2995  {
2996  return null;
2997  }
2998  }
2999 
3000  public function get_name()
3001  {
3002  if ($this->name !== null)
3003  {
3004  return $this->name;
3005  }
3006  else
3007  {
3008  return null;
3009  }
3010  }
3011 }
3013 {
3014 
3015  var $data = '';
3016 
3017  var $consumed = '';
3018 
3019  var $position = 0;
3020 
3021  public function __construct($data)
3022  {
3023  $this->data = $data;
3024  }
3025 
3026  public function parse()
3027  {
3028  while (($this->position = strpos($this->data, '&', $this->position)) !== false)
3029  {
3030  $this->consume();
3031  $this->entity();
3032  $this->consumed = '';
3033  }
3034  return $this->data;
3035  }
3036 
3037  public function consume()
3038  {
3039  if (isset($this->data[$this->position]))
3040  {
3041  $this->consumed .= $this->data[$this->position];
3042  return $this->data[$this->position++];
3043  }
3044  else
3045  {
3046  return false;
3047  }
3048  }
3049 
3050  public function consume_range($chars)
3051  {
3052  if ($len = strspn($this->data, $chars, $this->position))
3053  {
3054  $data = substr($this->data, $this->position, $len);
3055  $this->consumed .= $data;
3056  $this->position += $len;
3057  return $data;
3058  }
3059  else
3060  {
3061  return false;
3062  }
3063  }
3064 
3065  public function unconsume()
3066  {
3067  $this->consumed = substr($this->consumed, 0, -1);
3068  $this->position--;
3069  }
3070 
3071  public function entity()
3072  {
3073  switch ($this->consume())
3074  {
3075  case "\x09":
3076  case "\x0A":
3077  case "\x0B":
3078  case "\x0B":
3079  case "\x0C":
3080  case "\x20":
3081  case "\x3C":
3082  case "\x26":
3083  case false:
3084  break;
3085  case "\x23":
3086  switch ($this->consume())
3087  {
3088  case "\x78":
3089  case "\x58":
3090  $range = '0123456789ABCDEFabcdef';
3091  $hex = true;
3092  break;
3093  default:
3094  $range = '0123456789';
3095  $hex = false;
3096  $this->unconsume();
3097  break;
3098  }
3099  if ($codepoint = $this->consume_range($range))
3100  {
3101  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");
3102  if ($hex)
3103  {
3104  $codepoint = hexdec($codepoint);
3105  }
3106  else
3107  {
3108  $codepoint = intval($codepoint);
3109  }
3110  if (isset($windows_1252_specials[$codepoint]))
3111  {
3112  $replacement = $windows_1252_specials[$codepoint];
3113  }
3114  else
3115  {
3116  $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
3117  }
3118  if (!in_array($this->consume(), array(';', false), true))
3119  {
3120  $this->unconsume();
3121  }
3122  $consumed_length = strlen($this->consumed);
3123  $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
3124  $this->position += strlen($replacement) - $consumed_length;
3125  }
3126  break;
3127  default:
3128  static $entities = array(
3129  'Aacute' => "\xC3\x81",
3130  'aacute' => "\xC3\xA1",
3131  'Aacute;' => "\xC3\x81",
3132  'aacute;' => "\xC3\xA1",
3133  'Acirc' => "\xC3\x82",
3134  'acirc' => "\xC3\xA2",
3135  'Acirc;' => "\xC3\x82",
3136  'acirc;' => "\xC3\xA2",
3137  'acute' => "\xC2\xB4",
3138  'acute;' => "\xC2\xB4",
3139  'AElig' => "\xC3\x86",
3140  'aelig' => "\xC3\xA6",
3141  'AElig;' => "\xC3\x86",
3142  'aelig;' => "\xC3\xA6",
3143  'Agrave' => "\xC3\x80",
3144  'agrave' => "\xC3\xA0",
3145  'Agrave;' => "\xC3\x80",
3146  'agrave;' => "\xC3\xA0",
3147  'alefsym;' => "\xE2\x84\xB5",
3148  'Alpha;' => "\xCE\x91",
3149  'alpha;' => "\xCE\xB1",
3150  'AMP' => "\x26",
3151  'amp' => "\x26",
3152  'AMP;' => "\x26",
3153  'amp;' => "\x26",
3154  'and;' => "\xE2\x88\xA7",
3155  'ang;' => "\xE2\x88\xA0",
3156  'apos;' => "\x27",
3157  'Aring' => "\xC3\x85",
3158  'aring' => "\xC3\xA5",
3159  'Aring;' => "\xC3\x85",
3160  'aring;' => "\xC3\xA5",
3161  'asymp;' => "\xE2\x89\x88",
3162  'Atilde' => "\xC3\x83",
3163  'atilde' => "\xC3\xA3",
3164  'Atilde;' => "\xC3\x83",
3165  'atilde;' => "\xC3\xA3",
3166  'Auml' => "\xC3\x84",
3167  'auml' => "\xC3\xA4",
3168  'Auml;' => "\xC3\x84",
3169  'auml;' => "\xC3\xA4",
3170  'bdquo;' => "\xE2\x80\x9E",
3171  'Beta;' => "\xCE\x92",
3172  'beta;' => "\xCE\xB2",
3173  'brvbar' => "\xC2\xA6",
3174  'brvbar;' => "\xC2\xA6",
3175  'bull;' => "\xE2\x80\xA2",
3176  'cap;' => "\xE2\x88\xA9",
3177  'Ccedil' => "\xC3\x87",
3178  'ccedil' => "\xC3\xA7",
3179  'Ccedil;' => "\xC3\x87",
3180  'ccedil;' => "\xC3\xA7",
3181  'cedil' => "\xC2\xB8",
3182  'cedil;' => "\xC2\xB8",
3183  'cent' => "\xC2\xA2",
3184  'cent;' => "\xC2\xA2",
3185  'Chi;' => "\xCE\xA7",
3186  'chi;' => "\xCF\x87",
3187  'circ;' => "\xCB\x86",
3188  'clubs;' => "\xE2\x99\xA3",
3189  'cong;' => "\xE2\x89\x85",
3190  'COPY' => "\xC2\xA9",
3191  'copy' => "\xC2\xA9",
3192  'COPY;' => "\xC2\xA9",
3193  'copy;' => "\xC2\xA9",
3194  'crarr;' => "\xE2\x86\xB5",
3195  'cup;' => "\xE2\x88\xAA",
3196  'curren' => "\xC2\xA4",
3197  'curren;' => "\xC2\xA4",
3198  'Dagger;' => "\xE2\x80\xA1",
3199  'dagger;' => "\xE2\x80\xA0",
3200  'dArr;' => "\xE2\x87\x93",
3201  'darr;' => "\xE2\x86\x93",
3202  'deg' => "\xC2\xB0",
3203  'deg;' => "\xC2\xB0",
3204  'Delta;' => "\xCE\x94",
3205  'delta;' => "\xCE\xB4",
3206  'diams;' => "\xE2\x99\xA6",
3207  'divide' => "\xC3\xB7",
3208  'divide;' => "\xC3\xB7",
3209  'Eacute' => "\xC3\x89",
3210  'eacute' => "\xC3\xA9",
3211  'Eacute;' => "\xC3\x89",
3212  'eacute;' => "\xC3\xA9",
3213  'Ecirc' => "\xC3\x8A",
3214  'ecirc' => "\xC3\xAA",
3215  'Ecirc;' => "\xC3\x8A",
3216  'ecirc;' => "\xC3\xAA",
3217  'Egrave' => "\xC3\x88",
3218  'egrave' => "\xC3\xA8",
3219  'Egrave;' => "\xC3\x88",
3220  'egrave;' => "\xC3\xA8",
3221  'empty;' => "\xE2\x88\x85",
3222  'emsp;' => "\xE2\x80\x83",
3223  'ensp;' => "\xE2\x80\x82",
3224  'Epsilon;' => "\xCE\x95",
3225  'epsilon;' => "\xCE\xB5",
3226  'equiv;' => "\xE2\x89\xA1",
3227  'Eta;' => "\xCE\x97",
3228  'eta;' => "\xCE\xB7",
3229  'ETH' => "\xC3\x90",
3230  'eth' => "\xC3\xB0",
3231  'ETH;' => "\xC3\x90",
3232  'eth;' => "\xC3\xB0",
3233  'Euml' => "\xC3\x8B",
3234  'euml' => "\xC3\xAB",
3235  'Euml;' => "\xC3\x8B",
3236  'euml;' => "\xC3\xAB",
3237  'euro;' => "\xE2\x82\xAC",
3238  'exist;' => "\xE2\x88\x83",
3239  'fnof;' => "\xC6\x92",
3240  'forall;' => "\xE2\x88\x80",
3241  'frac12' => "\xC2\xBD",
3242  'frac12;' => "\xC2\xBD",
3243  'frac14' => "\xC2\xBC",
3244  'frac14;' => "\xC2\xBC",
3245  'frac34' => "\xC2\xBE",
3246  'frac34;' => "\xC2\xBE",
3247  'frasl;' => "\xE2\x81\x84",
3248  'Gamma;' => "\xCE\x93",
3249  'gamma;' => "\xCE\xB3",
3250  'ge;' => "\xE2\x89\xA5",
3251  'GT' => "\x3E",
3252  'gt' => "\x3E",
3253  'GT;' => "\x3E",
3254  'gt;' => "\x3E",
3255  'hArr;' => "\xE2\x87\x94",
3256  'harr;' => "\xE2\x86\x94",
3257  'hearts;' => "\xE2\x99\xA5",
3258  'hellip;' => "\xE2\x80\xA6",
3259  'Iacute' => "\xC3\x8D",
3260  'iacute' => "\xC3\xAD",
3261  'Iacute;' => "\xC3\x8D",
3262  'iacute;' => "\xC3\xAD",
3263  'Icirc' => "\xC3\x8E",
3264  'icirc' => "\xC3\xAE",
3265  'Icirc;' => "\xC3\x8E",
3266  'icirc;' => "\xC3\xAE",
3267  'iexcl' => "\xC2\xA1",
3268  'iexcl;' => "\xC2\xA1",
3269  'Igrave' => "\xC3\x8C",
3270  'igrave' => "\xC3\xAC",
3271  'Igrave;' => "\xC3\x8C",
3272  'igrave;' => "\xC3\xAC",
3273  'image;' => "\xE2\x84\x91",
3274  'infin;' => "\xE2\x88\x9E",
3275  'int;' => "\xE2\x88\xAB",
3276  'Iota;' => "\xCE\x99",
3277  'iota;' => "\xCE\xB9",
3278  'iquest' => "\xC2\xBF",
3279  'iquest;' => "\xC2\xBF",
3280  'isin;' => "\xE2\x88\x88",
3281  'Iuml' => "\xC3\x8F",
3282  'iuml' => "\xC3\xAF",
3283  'Iuml;' => "\xC3\x8F",
3284  'iuml;' => "\xC3\xAF",
3285  'Kappa;' => "\xCE\x9A",
3286  'kappa;' => "\xCE\xBA",
3287  'Lambda;' => "\xCE\x9B",
3288  'lambda;' => "\xCE\xBB",
3289  'lang;' => "\xE3\x80\x88",
3290  'laquo' => "\xC2\xAB",
3291  'laquo;' => "\xC2\xAB",
3292  'lArr;' => "\xE2\x87\x90",
3293  'larr;' => "\xE2\x86\x90",
3294  'lceil;' => "\xE2\x8C\x88",
3295  'ldquo;' => "\xE2\x80\x9C",
3296  'le;' => "\xE2\x89\xA4",
3297  'lfloor;' => "\xE2\x8C\x8A",
3298  'lowast;' => "\xE2\x88\x97",
3299  'loz;' => "\xE2\x97\x8A",
3300  'lrm;' => "\xE2\x80\x8E",
3301  'lsaquo;' => "\xE2\x80\xB9",
3302  'lsquo;' => "\xE2\x80\x98",
3303  'LT' => "\x3C",
3304  'lt' => "\x3C",
3305  'LT;' => "\x3C",
3306  'lt;' => "\x3C",
3307  'macr' => "\xC2\xAF",
3308  'macr;' => "\xC2\xAF",
3309  'mdash;' => "\xE2\x80\x94",
3310  'micro' => "\xC2\xB5",
3311  'micro;' => "\xC2\xB5",
3312  'middot' => "\xC2\xB7",
3313  'middot;' => "\xC2\xB7",
3314  'minus;' => "\xE2\x88\x92",
3315  'Mu;' => "\xCE\x9C",
3316  'mu;' => "\xCE\xBC",
3317  'nabla;' => "\xE2\x88\x87",
3318  'nbsp' => "\xC2\xA0",
3319  'nbsp;' => "\xC2\xA0",
3320  'ndash;' => "\xE2\x80\x93",
3321  'ne;' => "\xE2\x89\xA0",
3322  'ni;' => "\xE2\x88\x8B",
3323  'not' => "\xC2\xAC",
3324  'not;' => "\xC2\xAC",
3325  'notin;' => "\xE2\x88\x89",
3326  'nsub;' => "\xE2\x8A\x84",
3327  'Ntilde' => "\xC3\x91",
3328  'ntilde' => "\xC3\xB1",
3329  'Ntilde;' => "\xC3\x91",
3330  'ntilde;' => "\xC3\xB1",
3331  'Nu;' => "\xCE\x9D",
3332  'nu;' => "\xCE\xBD",
3333  'Oacute' => "\xC3\x93",
3334  'oacute' => "\xC3\xB3",
3335  'Oacute;' => "\xC3\x93",
3336  'oacute;' => "\xC3\xB3",
3337  'Ocirc' => "\xC3\x94",
3338  'ocirc' => "\xC3\xB4",
3339  'Ocirc;' => "\xC3\x94",
3340  'ocirc;' => "\xC3\xB4",
3341  'OElig;' => "\xC5\x92",
3342  'oelig;' => "\xC5\x93",
3343  'Ograve' => "\xC3\x92",
3344  'ograve' => "\xC3\xB2",
3345  'Ograve;' => "\xC3\x92",
3346  'ograve;' => "\xC3\xB2",
3347  'oline;' => "\xE2\x80\xBE",
3348  'Omega;' => "\xCE\xA9",
3349  'omega;' => "\xCF\x89",
3350  'Omicron;' => "\xCE\x9F",
3351  'omicron;' => "\xCE\xBF",
3352  'oplus;' => "\xE2\x8A\x95",
3353  'or;' => "\xE2\x88\xA8",
3354  'ordf' => "\xC2\xAA",
3355  'ordf;' => "\xC2\xAA",
3356  'ordm' => "\xC2\xBA",
3357  'ordm;' => "\xC2\xBA",
3358  'Oslash' => "\xC3\x98",
3359  'oslash' => "\xC3\xB8",
3360  'Oslash;' => "\xC3\x98",
3361  'oslash;' => "\xC3\xB8",
3362  'Otilde' => "\xC3\x95",
3363  'otilde' => "\xC3\xB5",
3364  'Otilde;' => "\xC3\x95",
3365  'otilde;' => "\xC3\xB5",
3366  'otimes;' => "\xE2\x8A\x97",
3367  'Ouml' => "\xC3\x96",
3368  'ouml' => "\xC3\xB6",
3369  'Ouml;' => "\xC3\x96",
3370  'ouml;' => "\xC3\xB6",
3371  'para' => "\xC2\xB6",
3372  'para;' => "\xC2\xB6",
3373  'part;' => "\xE2\x88\x82",
3374  'permil;' => "\xE2\x80\xB0",
3375  'perp;' => "\xE2\x8A\xA5",
3376  'Phi;' => "\xCE\xA6",
3377  'phi;' => "\xCF\x86",
3378  'Pi;' => "\xCE\xA0",
3379  'pi;' => "\xCF\x80",
3380  'piv;' => "\xCF\x96",
3381  'plusmn' => "\xC2\xB1",
3382  'plusmn;' => "\xC2\xB1",
3383  'pound' => "\xC2\xA3",
3384  'pound;' => "\xC2\xA3",
3385  'Prime;' => "\xE2\x80\xB3",
3386  'prime;' => "\xE2\x80\xB2",
3387  'prod;' => "\xE2\x88\x8F",
3388  'prop;' => "\xE2\x88\x9D",
3389  'Psi;' => "\xCE\xA8",
3390  'psi;' => "\xCF\x88",
3391  'QUOT' => "\x22",
3392  'quot' => "\x22",
3393  'QUOT;' => "\x22",
3394  'quot;' => "\x22",
3395  'radic;' => "\xE2\x88\x9A",
3396  'rang;' => "\xE3\x80\x89",
3397  'raquo' => "\xC2\xBB",
3398  'raquo;' => "\xC2\xBB",
3399  'rArr;' => "\xE2\x87\x92",
3400  'rarr;' => "\xE2\x86\x92",
3401  'rceil;' => "\xE2\x8C\x89",
3402  'rdquo;' => "\xE2\x80\x9D",
3403  'real;' => "\xE2\x84\x9C",
3404  'REG' => "\xC2\xAE",
3405  'reg' => "\xC2\xAE",
3406  'REG;' => "\xC2\xAE",
3407  'reg;' => "\xC2\xAE",
3408  'rfloor;' => "\xE2\x8C\x8B",
3409  'Rho;' => "\xCE\xA1",
3410  'rho;' => "\xCF\x81",
3411  'rlm;' => "\xE2\x80\x8F",
3412  'rsaquo;' => "\xE2\x80\xBA",
3413  'rsquo;' => "\xE2\x80\x99",
3414  'sbquo;' => "\xE2\x80\x9A",
3415  'Scaron;' => "\xC5\xA0",
3416  'scaron;' => "\xC5\xA1",
3417  'sdot;' => "\xE2\x8B\x85",
3418  'sect' => "\xC2\xA7",
3419  'sect;' => "\xC2\xA7",
3420  'shy' => "\xC2\xAD",
3421  'shy;' => "\xC2\xAD",
3422  'Sigma;' => "\xCE\xA3",
3423  'sigma;' => "\xCF\x83",
3424  'sigmaf;' => "\xCF\x82",
3425  'sim;' => "\xE2\x88\xBC",
3426  'spades;' => "\xE2\x99\xA0",
3427  'sub;' => "\xE2\x8A\x82",
3428  'sube;' => "\xE2\x8A\x86",
3429  'sum;' => "\xE2\x88\x91",
3430  'sup;' => "\xE2\x8A\x83",
3431  'sup1' => "\xC2\xB9",
3432  'sup1;' => "\xC2\xB9",
3433  'sup2' => "\xC2\xB2",
3434  'sup2;' => "\xC2\xB2",
3435  'sup3' => "\xC2\xB3",
3436  'sup3;' => "\xC2\xB3",
3437  'supe;' => "\xE2\x8A\x87",
3438  'szlig' => "\xC3\x9F",
3439  'szlig;' => "\xC3\x9F",
3440  'Tau;' => "\xCE\xA4",
3441  'tau;' => "\xCF\x84",
3442  'there4;' => "\xE2\x88\xB4",
3443  'Theta;' => "\xCE\x98",
3444  'theta;' => "\xCE\xB8",
3445  'thetasym;' => "\xCF\x91",
3446  'thinsp;' => "\xE2\x80\x89",
3447  'THORN' => "\xC3\x9E",
3448  'thorn' => "\xC3\xBE",
3449  'THORN;' => "\xC3\x9E",
3450  'thorn;' => "\xC3\xBE",
3451  'tilde;' => "\xCB\x9C",
3452  'times' => "\xC3\x97",
3453  'times;' => "\xC3\x97",
3454  'TRADE;' => "\xE2\x84\xA2",
3455  'trade;' => "\xE2\x84\xA2",
3456  'Uacute' => "\xC3\x9A",
3457  'uacute' => "\xC3\xBA",
3458  'Uacute;' => "\xC3\x9A",
3459  'uacute;' => "\xC3\xBA",
3460  'uArr;' => "\xE2\x87\x91",
3461  'uarr;' => "\xE2\x86\x91",
3462  'Ucirc' => "\xC3\x9B",
3463  'ucirc' => "\xC3\xBB",
3464  'Ucirc;' => "\xC3\x9B",
3465  'ucirc;' => "\xC3\xBB",
3466  'Ugrave' => "\xC3\x99",
3467  'ugrave' => "\xC3\xB9",
3468  'Ugrave;' => "\xC3\x99",
3469  'ugrave;' => "\xC3\xB9",
3470  'uml' => "\xC2\xA8",
3471  'uml;' => "\xC2\xA8",
3472  'upsih;' => "\xCF\x92",
3473  'Upsilon;' => "\xCE\xA5",
3474  'upsilon;' => "\xCF\x85",
3475  'Uuml' => "\xC3\x9C",
3476  'uuml' => "\xC3\xBC",
3477  'Uuml;' => "\xC3\x9C",
3478  'uuml;' => "\xC3\xBC",
3479  'weierp;' => "\xE2\x84\x98",
3480  'Xi;' => "\xCE\x9E",
3481  'xi;' => "\xCE\xBE",
3482  'Yacute' => "\xC3\x9D",
3483  'yacute' => "\xC3\xBD",
3484  'Yacute;' => "\xC3\x9D",
3485  'yacute;' => "\xC3\xBD",
3486  'yen' => "\xC2\xA5",
3487  'yen;' => "\xC2\xA5",
3488  'yuml' => "\xC3\xBF",
3489  'Yuml;' => "\xC5\xB8",
3490  'yuml;' => "\xC3\xBF",
3491  'Zeta;' => "\xCE\x96",
3492  'zeta;' => "\xCE\xB6",
3493  'zwj;' => "\xE2\x80\x8D",
3494  'zwnj;' => "\xE2\x80\x8C"
3495  );
3496  for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
3497  {
3498  $consumed = substr($this->consumed, 1);
3499  if (isset($entities[$consumed]))
3500  {
3501  $match = $consumed;
3502  }
3503  }
3504  if ($match !== null)
3505  {
3506  $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
3507  $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
3508  }
3509  break;
3510  }
3511  }
3512 }
3514 {
3515 
3517 
3519 
3521 
3523 
3525 
3527 
3529 
3531 
3533 
3535 
3537 
3538  var $hashes;
3539 
3540  var $height;
3541 
3543 
3545 
3546  var $lang;
3547 
3548  var $length;
3549 
3550  var $link;
3551 
3552  var $medium;
3553 
3554  var $player;
3555 
3557 
3559 
3561 
3563 
3564  var $title;
3565 
3566  var $type;
3567 
3568  var $width;
3569 
3570  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)
3571  {
3572  $this->bitrate = $bitrate;
3573  $this->captions = $captions;
3574  $this->categories = $categories;
3575  $this->channels = $channels;
3576  $this->copyright = $copyright;
3577  $this->credits = $credits;
3578  $this->description = $description;
3579  $this->duration = $duration;
3580  $this->expression = $expression;
3581  $this->framerate = $framerate;
3582  $this->hashes = $hashes;
3583  $this->height = $height;
3584  $this->keywords = $keywords;
3585  $this->lang = $lang;
3586  $this->length = $length;
3587  $this->link = $link;
3588  $this->medium = $medium;
3589  $this->player = $player;
3590  $this->ratings = $ratings;
3591  $this->restrictions = $restrictions;
3592  $this->samplingrate = $samplingrate;
3593  $this->thumbnails = $thumbnails;
3594  $this->title = $title;
3595  $this->type = $type;
3596  $this->width = $width;
3597  if (class_exists('idna_convert'))
3598  {
3599  $idn = new idna_convert();
3600  $parsed = SimplePie_Misc::parse_url($link);
3601  $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
3602  }
3603  $this->handler = $this->get_handler(); // Needs to load last
3604  }
3605 
3606  public function __toString()
3607  {
3608  // There is no $this->data here
3609  return md5(serialize($this));
3610  }
3611 
3612  public function get_bitrate()
3613  {
3614  if ($this->bitrate !== null)
3615  {
3616  return $this->bitrate;
3617  }
3618  else
3619  {
3620  return null;
3621  }
3622  }
3623 
3624  public function get_caption($key = 0)
3625  {
3626  $captions = $this->get_captions();
3627  if (isset($captions[$key]))
3628  {
3629  return $captions[$key];
3630  }
3631  else
3632  {
3633  return null;
3634  }
3635  }
3636 
3637  public function get_captions()
3638  {
3639  if ($this->captions !== null)
3640  {
3641  return $this->captions;
3642  }
3643  else
3644  {
3645  return null;
3646  }
3647  }
3648 
3649  public function get_category($key = 0)
3650  {
3651  $categories = $this->get_categories();
3652  if (isset($categories[$key]))
3653  {
3654  return $categories[$key];
3655  }
3656  else
3657  {
3658  return null;
3659  }
3660  }
3661 
3662  public function get_categories()
3663  {
3664  if ($this->categories !== null)
3665  {
3666  return $this->categories;
3667  }
3668  else
3669  {
3670  return null;
3671  }
3672  }
3673 
3674  public function get_channels()
3675  {
3676  if ($this->channels !== null)
3677  {
3678  return $this->channels;
3679  }
3680  else
3681  {
3682  return null;
3683  }
3684  }
3685 
3686  public function get_copyright()
3687  {
3688  if ($this->copyright !== null)
3689  {
3690  return $this->copyright;
3691  }
3692  else
3693  {
3694  return null;
3695  }
3696  }
3697 
3698  public function get_credit($key = 0)
3699  {
3700  $credits = $this->get_credits();
3701  if (isset($credits[$key]))
3702  {
3703  return $credits[$key];
3704  }
3705  else
3706  {
3707  return null;
3708  }
3709  }
3710 
3711  public function get_credits()
3712  {
3713  if ($this->credits !== null)
3714  {
3715  return $this->credits;
3716  }
3717  else
3718  {
3719  return null;
3720  }
3721  }
3722 
3723  public function get_description()
3724  {
3725  if ($this->description !== null)
3726  {
3727  return $this->description;
3728  }
3729  else
3730  {
3731  return null;
3732  }
3733  }
3734 
3735  public function get_duration($convert = false)
3736  {
3737  if ($this->duration !== null)
3738  {
3739  if ($convert)
3740  {
3741  $time = SimplePie_Misc::time_hms($this->duration);
3742  return $time;
3743  }
3744  else
3745  {
3746  return $this->duration;
3747  }
3748  }
3749  else
3750  {
3751  return null;
3752  }
3753  }
3754 
3755  public function get_expression()
3756  {
3757  if ($this->expression !== null)
3758  {
3759  return $this->expression;
3760  }
3761  else
3762  {
3763  return 'full';
3764  }
3765  }
3766 
3767  public function get_extension()
3768  {
3769  if ($this->link !== null)
3770  {
3771  $url = SimplePie_Misc::parse_url($this->link);
3772  if ($url['path'] !== '')
3773  {
3774  return pathinfo($url['path'], PATHINFO_EXTENSION);
3775  }
3776  }
3777  return null;
3778  }
3779 
3780  public function get_framerate()
3781  {
3782  if ($this->framerate !== null)
3783  {
3784  return $this->framerate;
3785  }
3786  else
3787  {
3788  return null;
3789  }
3790  }
3791 
3792  public function get_handler()
3793  {
3794  return $this->get_real_type(true);
3795  }
3796 
3797  public function get_hash($key = 0)
3798  {
3799  $hashes = $this->get_hashes();
3800  if (isset($hashes[$key]))
3801  {
3802  return $hashes[$key];
3803  }
3804  else
3805  {
3806  return null;
3807  }
3808  }
3809 
3810  public function get_hashes()
3811  {
3812  if ($this->hashes !== null)
3813  {
3814  return $this->hashes;
3815  }
3816  else
3817  {
3818  return null;
3819  }
3820  }
3821 
3822  public function get_height()
3823  {
3824  if ($this->height !== null)
3825  {
3826  return $this->height;
3827  }
3828  else
3829  {
3830  return null;
3831  }
3832  }
3833 
3834  public function get_language()
3835  {
3836  if ($this->lang !== null)
3837  {
3838  return $this->lang;
3839  }
3840  else
3841  {
3842  return null;
3843  }
3844  }
3845 
3846  public function get_keyword($key = 0)
3847  {
3848  $keywords = $this->get_keywords();
3849  if (isset($keywords[$key]))
3850  {
3851  return $keywords[$key];
3852  }
3853  else
3854  {
3855  return null;
3856  }
3857  }
3858 
3859  public function get_keywords()
3860  {
3861  if ($this->keywords !== null)
3862  {
3863  return $this->keywords;
3864  }
3865  else
3866  {
3867  return null;
3868  }
3869  }
3870 
3871  public function get_length()
3872  {
3873  if ($this->length !== null)
3874  {
3875  return $this->length;
3876  }
3877  else
3878  {
3879  return null;
3880  }
3881  }
3882 
3883  public function get_link()
3884  {
3885  if ($this->link !== null)
3886  {
3887  return urldecode($this->link);
3888  }
3889  else
3890  {
3891  return null;
3892  }
3893  }
3894 
3895  public function get_medium()
3896  {
3897  if ($this->medium !== null)
3898  {
3899  return $this->medium;
3900  }
3901  else
3902  {
3903  return null;
3904  }
3905  }
3906 
3907  public function get_player()
3908  {
3909  if ($this->player !== null)
3910  {
3911  return $this->player;
3912  }
3913  else
3914  {
3915  return null;
3916  }
3917  }
3918 
3919  public function get_rating($key = 0)
3920  {
3921  $ratings = $this->get_ratings();
3922  if (isset($ratings[$key]))
3923  {
3924  return $ratings[$key];
3925  }
3926  else
3927  {
3928  return null;
3929  }
3930  }
3931 
3932  public function get_ratings()
3933  {
3934  if ($this->ratings !== null)
3935  {
3936  return $this->ratings;
3937  }
3938  else
3939  {
3940  return null;
3941  }
3942  }
3943 
3944  public function get_restriction($key = 0)
3945  {
3946  $restrictions = $this->get_restrictions();
3947  if (isset($restrictions[$key]))
3948  {
3949  return $restrictions[$key];
3950  }
3951  else
3952  {
3953  return null;
3954  }
3955  }
3956 
3957  public function get_restrictions()
3958  {
3959  if ($this->restrictions !== null)
3960  {
3961  return $this->restrictions;
3962  }
3963  else
3964  {
3965  return null;
3966  }
3967  }
3968 
3969  public function get_sampling_rate()
3970  {
3971  if ($this->samplingrate !== null)
3972  {
3973  return $this->samplingrate;
3974  }
3975  else
3976  {
3977  return null;
3978  }
3979  }
3980 
3981  public function get_size()
3982  {
3983  $length = $this->get_length();
3984  if ($length !== null)
3985  {
3986  return round($length/1048576, 2);
3987  }
3988  else
3989  {
3990  return null;
3991  }
3992  }
3993 
3994  public function get_thumbnail($key = 0)
3995  {
3996  $thumbnails = $this->get_thumbnails();
3997  if (isset($thumbnails[$key]))
3998  {
3999  return $thumbnails[$key];
4000  }
4001  else
4002  {
4003  return null;
4004  }
4005  }
4006 
4007  public function get_thumbnails()
4008  {
4009  if ($this->thumbnails !== null)
4010  {
4011  return $this->thumbnails;
4012  }
4013  else
4014  {
4015  return null;
4016  }
4017  }
4018 
4019  public function get_title()
4020  {
4021  if ($this->title !== null)
4022  {
4023  return $this->title;
4024  }
4025  else
4026  {
4027  return null;
4028  }
4029  }
4030 
4031  public function get_type()
4032  {
4033  if ($this->type !== null)
4034  {
4035  return $this->type;
4036  }
4037  else
4038  {
4039  return null;
4040  }
4041  }
4042 
4043  public function get_width()
4044  {
4045  if ($this->width !== null)
4046  {
4047  return $this->width;
4048  }
4049  else
4050  {
4051  return null;
4052  }
4053  }
4054 
4055  public function native_embed($options='')
4056  {
4057  return $this->embed($options, true);
4058  }
4059 
4060  public function embed($options = '', $native = false)
4061  {
4062  // Set up defaults
4063  $audio = '';
4064  $video = '';
4065  $alt = '';
4066  $altclass = '';
4067  $loop = 'false';
4068  $width = 'auto';
4069  $height = 'auto';
4070  $bgcolor = '#ffffff';
4071  $mediaplayer = '';
4072  $widescreen = false;
4073  $handler = $this->get_handler();
4074  $type = $this->get_real_type();
4075  // Process options and reassign values as necessary
4076  if (is_array($options))
4077  {
4078  extract($options);
4079  }
4080  else
4081  {
4082  $options = explode(',', $options);
4083  foreach($options as $option)
4084  {
4085  $opt = explode(':', $option, 2);
4086  if (isset($opt[0], $opt[1]))
4087  {
4088  $opt[0] = trim($opt[0]);
4089  $opt[1] = trim($opt[1]);
4090  switch ($opt[0])
4091  {
4092  case 'audio':
4093  $audio = $opt[1];
4094  break;
4095  case 'video':
4096  $video = $opt[1];
4097  break;
4098  case 'alt':
4099  $alt = $opt[1];
4100  break;
4101  case 'altclass':
4102  $altclass = $opt[1];
4103  break;
4104  case 'loop':
4105  $loop = $opt[1];
4106  break;
4107  case 'width':
4108  $width = $opt[1];
4109  break;
4110  case 'height':
4111  $height = $opt[1];
4112  break;
4113  case 'bgcolor':
4114  $bgcolor = $opt[1];
4115  break;
4116  case 'mediaplayer':
4117  $mediaplayer = $opt[1];
4118  break;
4119  case 'widescreen':
4120  $widescreen = $opt[1];
4121  break;
4122  }
4123  }
4124  }
4125  }
4126  $mime = explode('/', $type, 2);
4127  $mime = $mime[0];
4128  // Process values for 'auto'
4129  if ($width === 'auto')
4130  {
4131  if ($mime === 'video')
4132  {
4133  if ($height === 'auto')
4134  {
4135  $width = 480;
4136  }
4137  elseif ($widescreen)
4138  {
4139  $width = round((intval($height)/9)*16);
4140  }
4141  else
4142  {
4143  $width = round((intval($height)/3)*4);
4144  }
4145  }
4146  else
4147  {
4148  $width = '100%';
4149  }
4150  }
4151  if ($height === 'auto')
4152  {
4153  if ($mime === 'audio')
4154  {
4155  $height = 0;
4156  }
4157  elseif ($mime === 'video')
4158  {
4159  if ($width === 'auto')
4160  {
4161  if ($widescreen)
4162  {
4163  $height = 270;
4164  }
4165  else
4166  {
4167  $height = 360;
4168  }
4169  }
4170  elseif ($widescreen)
4171  {
4172  $height = round((intval($width)/16)*9);
4173  }
4174  else
4175  {
4176  $height = round((intval($width)/4)*3);
4177  }
4178  }
4179  else
4180  {
4181  $height = 376;
4182  }
4183  }
4184  elseif ($mime === 'audio')
4185  {
4186  $height = 0;
4187  }
4188  // Set proper placeholder value
4189  if ($mime === 'audio')
4190  {
4191  $placeholder = $audio;
4192  }
4193  elseif ($mime === 'video')
4194  {
4195  $placeholder = $video;
4196  }
4197  $embed = '';
4198  // Flash
4199  if ($handler === 'flash')
4200  {
4201  if ($native)
4202  {
4203  $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>";
4204  }
4205  else
4206  {
4207  $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
4208  }
4209  }
4210  // Flash Media Player file types.
4211  // Preferred handler for MP3 file types.
4212  elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
4213  {
4214  $height += 20;
4215  if ($native)
4216  {
4217  $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>";
4218  }
4219  else
4220  {
4221  $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
4222  }
4223  }
4224  // QuickTime 7 file types. Need to test with QuickTime 6.
4225  // Only handle MP3's if the Flash Media Player is not present.
4226  elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
4227  {
4228  $height += 16;
4229  if ($native)
4230  {
4231  if ($placeholder !== '')
4232  {
4233  $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>";
4234  }
4235  else
4236  {
4237  $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>";
4238  }
4239  }
4240  else
4241  {
4242  $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
4243  }
4244  }
4245  // Windows Media
4246  elseif ($handler === 'wmedia')
4247  {
4248  $height += 45;
4249  if ($native)
4250  {
4251  $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>";
4252  }
4253  else
4254  {
4255  $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
4256  }
4257  }
4258  // Everything else
4259  else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
4260  return $embed;
4261  }
4262 
4263  public function get_real_type($find_handler = false)
4264  {
4265  // Mime-types by handler.
4266  $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
4267  $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
4268  $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
4269  $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
4270  $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
4271  if ($this->get_type() !== null)
4272  {
4273  $type = strtolower($this->type);
4274  }
4275  else
4276  {
4277  $type = null;
4278  }
4279  // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
4280  if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
4281  {
4282  switch (strtolower($this->get_extension()))
4283  {
4284  // Audio mime-types
4285  case 'aac':
4286  case 'adts':
4287  $type = 'audio/acc';
4288  break;
4289  case 'aif':
4290  case 'aifc':
4291  case 'aiff':
4292  case 'cdda':
4293  $type = 'audio/aiff';
4294  break;
4295  case 'bwf':
4296  $type = 'audio/wav';
4297  break;
4298  case 'kar':
4299  case 'mid':
4300  case 'midi':
4301  case 'smf':
4302  $type = 'audio/midi';
4303  break;
4304  case 'm4a':
4305  $type = 'audio/x-m4a';
4306  break;
4307  case 'mp3':
4308  case 'swa':
4309  $type = 'audio/mp3';
4310  break;
4311  case 'wav':
4312  $type = 'audio/wav';
4313  break;
4314  case 'wax':
4315  $type = 'audio/x-ms-wax';
4316  break;
4317  case 'wma':
4318  $type = 'audio/x-ms-wma';
4319  break;
4320  // Video mime-types
4321  case '3gp':
4322  case '3gpp':
4323  $type = 'video/3gpp';
4324  break;
4325  case '3g2':
4326  case '3gp2':
4327  $type = 'video/3gpp2';
4328  break;
4329  case 'asf':
4330  $type = 'video/x-ms-asf';
4331  break;
4332  case 'flv':
4333  $type = 'video/x-flv';
4334  break;
4335  case 'm1a':
4336  case 'm1s':
4337  case 'm1v':
4338  case 'm15':
4339  case 'm75':
4340  case 'mp2':
4341  case 'mpa':
4342  case 'mpeg':
4343  case 'mpg':
4344  case 'mpm':
4345  case 'mpv':
4346  $type = 'video/mpeg';
4347  break;
4348  case 'm4v':
4349  $type = 'video/x-m4v';
4350  break;
4351  case 'mov':
4352  case 'qt':
4353  $type = 'video/quicktime';
4354  break;
4355  case 'mp4':
4356  case 'mpg4':
4357  $type = 'video/mp4';
4358  break;
4359  case 'sdv':
4360  $type = 'video/sd-video';
4361  break;
4362  case 'wm':
4363  $type = 'video/x-ms-wm';
4364  break;
4365  case 'wmv':
4366  $type = 'video/x-ms-wmv';
4367  break;
4368  case 'wvx':
4369  $type = 'video/x-ms-wvx';
4370  break;
4371  // Flash mime-types
4372  case 'spl':
4373  $type = 'application/futuresplash';
4374  break;
4375  case 'swf':
4376  $type = 'application/x-shockwave-flash';
4377  break;
4378  }
4379  }
4380  if ($find_handler)
4381  {
4382  if (in_array($type, $types_flash))
4383  {
4384  return 'flash';
4385  }
4386  elseif (in_array($type, $types_fmedia))
4387  {
4388  return 'fmedia';
4389  }
4390  elseif (in_array($type, $types_quicktime))
4391  {
4392  return 'quicktime';
4393  }
4394  elseif (in_array($type, $types_wmedia))
4395  {
4396  return 'wmedia';
4397  }
4398  elseif (in_array($type, $types_mp3))
4399  {
4400  return 'mp3';
4401  }
4402  else
4403  {
4404  return null;
4405  }
4406  }
4407  else
4408  {
4409  return $type;
4410  }
4411  }
4412 }
4413 class SimplePie_Exception extends Exception
4414 {
4415 }
4417 {
4418  var $url;
4420  var $success = true;
4421  var $headers = array();
4422  var $body;
4424  var $redirects = 0;
4425  var $error;
4427  public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
4428  {
4429  if (class_exists('idna_convert'))
4430  {
4431  $idn = new idna_convert();
4432  $parsed = SimplePie_Misc::parse_url($url);
4433  $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
4434  }
4435  $this->url = $url;
4436  $this->useragent = $useragent;
4437  if (preg_match('/^http(s)?:\/\//i', $url))
4438  {
4439  if ($useragent === null)
4440  {
4441  $useragent = ini_get('user_agent');
4442  $this->useragent = $useragent;
4443  }
4444  if (!is_array($headers))
4445  {
4446  $headers = array();
4447  }
4448  if (!$force_fsockopen && function_exists('curl_exec'))
4449  {
4451  $fp = curl_init();
4452  $headers2 = array();
4453  foreach ($headers as $key => $value)
4454  {
4455  $headers2[] = "$key: $value";
4456  }
4457  if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
4458  {
4459  curl_setopt($fp, CURLOPT_ENCODING, '');
4460  }
4461  curl_setopt($fp, CURLOPT_URL, $url);
4462  curl_setopt($fp, CURLOPT_HEADER, 1);
4463  curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
4464  curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
4465  curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
4466  curl_setopt($fp, CURLOPT_REFERER, $url);
4467  curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
4468  curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
4469  if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
4470  {
4471  curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
4472  curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
4473  }
4474  $this->headers = curl_exec($fp);
4475  if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
4476  {
4477  curl_setopt($fp, CURLOPT_ENCODING, 'none');
4478  $this->headers = curl_exec($fp);
4479  }
4480  if (curl_errno($fp))
4481  {
4482  $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
4483  $this->success = false;
4484  }
4485  else
4486  {
4487  $info = curl_getinfo($fp);
4488  curl_close($fp);
4489  $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
4490  $this->headers = array_pop($this->headers);
4491  $parser = new SimplePie_HTTP_Parser($this->headers);
4492  if ($parser->parse())
4493  {
4494  $this->headers = $parser->headers;
4495  $this->body = $parser->body;
4496  $this->status_code = $parser->status_code;
4497  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)
4498  {
4499  $this->redirects++;
4500  $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
4501  return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
4502  }
4503  }
4504  }
4505  }
4506  else
4507  {
4509  $url_parts = parse_url($url);
4510  $socket_host = $url_parts['host'];
4511  if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
4512  {
4513  $socket_host = "ssl://$url_parts[host]";
4514  $url_parts['port'] = 443;
4515  }
4516  if (!isset($url_parts['port']))
4517  {
4518  $url_parts['port'] = 80;
4519  }
4520  $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
4521  if (!$fp)
4522  {
4523  $this->error = 'fsockopen error: ' . $errstr;
4524  $this->success = false;
4525  }
4526  else
4527  {
4528  stream_set_timeout($fp, $timeout);
4529  if (isset($url_parts['path']))
4530  {
4531  if (isset($url_parts['query']))
4532  {
4533  $get = "$url_parts[path]?$url_parts[query]";
4534  }
4535  else
4536  {
4537  $get = $url_parts['path'];
4538  }
4539  }
4540  else
4541  {
4542  $get = '/';
4543  }
4544  $out = "GET $get HTTP/1.1\r\n";
4545  $out .= "Host: $url_parts[host]\r\n";
4546  $out .= "User-Agent: $useragent\r\n";
4547  if (extension_loaded('zlib'))
4548  {
4549  $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
4550  }
4551  if (isset($url_parts['user']) && isset($url_parts['pass']))
4552  {
4553  $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
4554  }
4555  foreach ($headers as $key => $value)
4556  {
4557  $out .= "$key: $value\r\n";
4558  }
4559  $out .= "Connection: Close\r\n\r\n";
4560  fwrite($fp, $out);
4561  $info = stream_get_meta_data($fp);
4562  $this->headers = '';
4563  while (!$info['eof'] && !$info['timed_out'])
4564  {
4565  $this->headers .= fread($fp, 1160);
4566  $info = stream_get_meta_data($fp);
4567  }
4568  if (!$info['timed_out'])
4569  {
4570  $parser = new SimplePie_HTTP_Parser($this->headers);
4571  if ($parser->parse())
4572  {
4573  $this->headers = $parser->headers;
4574  $this->body = $parser->body;
4575  $this->status_code = $parser->status_code;
4576  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)
4577  {
4578  $this->redirects++;
4579  $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
4580  return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
4581  }
4582  if (isset($this->headers['content-encoding']))
4583  {
4584  // Hey, we act dumb elsewhere, so let's do that here too
4585  switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
4586  {
4587  case 'gzip':
4588  case 'x-gzip':
4589  $decoder = new SimplePie_gzdecode($this->body);
4590  if (!$decoder->parse())
4591  {
4592  $this->error = 'Unable to decode HTTP "gzip" stream';
4593  $this->success = false;
4594  }
4595  else
4596  {
4597  $this->body = $decoder->data;
4598  }
4599  break;
4600  case 'deflate':
4601  if (($decompressed = gzinflate($this->body)) !== false)
4602  {
4603  $this->body = $decompressed;
4604  }
4605  else if (($decompressed = gzuncompress($this->body)) !== false)
4606  {
4607  $this->body = $decompressed;
4608  }
4609  else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
4610  {
4611  $this->body = $decompressed;
4612  }
4613  else
4614  {
4615  $this->error = 'Unable to decode HTTP "deflate" stream';
4616  $this->success = false;
4617  }
4618  break;
4619  default:
4620  $this->error = 'Unknown content coding';
4621  $this->success = false;
4622  }
4623  }
4624  }
4625  }
4626  else
4627  {
4628  $this->error = 'fsocket timed out';
4629  $this->success = false;
4630  }
4631  fclose($fp);
4632  }
4633  }
4634  }
4635  else
4636  {
4638  if (!$this->body = file_get_contents($url))
4639  {
4640  $this->error = 'file_get_contents could not read the file';
4641  $this->success = false;
4642  }
4643  }
4644  }
4645 }
4647 {
4648 
4650 
4652 
4654 
4655  var $position = 0;
4656 
4657  var $flags;
4658 
4659  var $data;
4660 
4661  var $MTIME;
4662 
4663  var $XFL;
4664 
4665  var $OS;
4666 
4667  var $SI1;
4668 
4669  var $SI2;
4670 
4672 
4674 
4676 
4677  public function __set($name, $value)
4678  {
4679  trigger_error("Cannot write property $name", E_USER_ERROR);
4680  }
4681 
4682  public function __construct($data)
4683  {
4684  $this->compressed_data = $data;
4685  $this->compressed_size = strlen($data);
4686  }
4687 
4688  public function parse()
4689  {
4690  if ($this->compressed_size >= $this->min_compressed_size)
4691  {
4692  // Check ID1, ID2, and CM
4693  if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
4694  {
4695  return false;
4696  }
4697  // Get the FLG (FLaGs)
4698  $this->flags = ord($this->compressed_data[3]);
4699  // FLG bits above (1 << 4) are reserved
4700  if ($this->flags > 0x1F)
4701  {
4702  return false;
4703  }
4704  // Advance the pointer after the above
4705  $this->position += 4;
4706  // MTIME
4707  $mtime = substr($this->compressed_data, $this->position, 4);
4708  // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
4709  if (current(unpack('S', "\x00\x01")) === 1)
4710  {
4711  $mtime = strrev($mtime);
4712  }
4713  $this->MTIME = current(unpack('l', $mtime));
4714  $this->position += 4;
4715  // Get the XFL (eXtra FLags)
4716  $this->XFL = ord($this->compressed_data[$this->position++]);
4717  // Get the OS (Operating System)
4718  $this->OS = ord($this->compressed_data[$this->position++]);
4719  // Parse the FEXTRA
4720  if ($this->flags & 4)
4721  {
4722  // Read subfield IDs
4723  $this->SI1 = $this->compressed_data[$this->position++];
4724  $this->SI2 = $this->compressed_data[$this->position++];
4725  // SI2 set to zero is reserved for future use
4726  if ($this->SI2 === "\x00")
4727  {
4728  return false;
4729  }
4730  // Get the length of the extra field
4731  $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
4732  $this->position += 2;
4733  // Check the length of the string is still valid
4734  $this->min_compressed_size += $len + 4;
4735  if ($this->compressed_size >= $this->min_compressed_size)
4736  {
4737  // Set the extra field to the given data
4738  $this->extra_field = substr($this->compressed_data, $this->position, $len);
4739  $this->position += $len;
4740  }
4741  else
4742  {
4743  return false;
4744  }
4745  }
4746  // Parse the FNAME
4747  if ($this->flags & 8)
4748  {
4749  // Get the length of the filename
4750  $len = strcspn($this->compressed_data, "\x00", $this->position);
4751  // Check the length of the string is still valid
4752  $this->min_compressed_size += $len + 1;
4753  if ($this->compressed_size >= $this->min_compressed_size)
4754  {
4755  // Set the original filename to the given string
4756  $this->filename = substr($this->compressed_data, $this->position, $len);
4757  $this->position += $len + 1;
4758  }
4759  else
4760  {
4761  return false;
4762  }
4763  }
4764  // Parse the FCOMMENT
4765  if ($this->flags & 16)
4766  {
4767  // Get the length of the comment
4768  $len = strcspn($this->compressed_data, "\x00", $this->position);
4769  // Check the length of the string is still valid
4770  $this->min_compressed_size += $len + 1;
4771  if ($this->compressed_size >= $this->min_compressed_size)
4772  {
4773  // Set the original comment to the given string
4774  $this->comment = substr($this->compressed_data, $this->position, $len);
4775  $this->position += $len + 1;
4776  }
4777  else
4778  {
4779  return false;
4780  }
4781  }
4782  // Parse the FHCRC
4783  if ($this->flags & 2)
4784  {
4785  // Check the length of the string is still valid
4786  $this->min_compressed_size += $len + 2;
4787  if ($this->compressed_size >= $this->min_compressed_size)
4788  {
4789  // Read the CRC
4790  $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
4791  // Check the CRC matches
4792  if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
4793  {
4794  $this->position += 2;
4795  }
4796  else
4797  {
4798  return false;
4799  }
4800  }
4801  else
4802  {
4803  return false;
4804  }
4805  }
4806  // Decompress the actual data
4807  if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
4808  {
4809  return false;
4810  }
4811  else
4812  {
4813  $this->position = $this->compressed_size - 8;
4814  }
4815  // Check CRC of data
4816  $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
4817  $this->position += 4;
4818  /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
4819  {
4820  return false;
4821  }*/
4822  // Check ISIZE of data
4823  $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
4824  $this->position += 4;
4825  if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
4826  {
4827  return false;
4828  }
4829  // Wow, against all odds, we've actually got a valid gzip string
4830  return true;
4831  }
4832  else
4833  {
4834  return false;
4835  }
4836  }
4837 }
4839 {
4840 
4841  public $http_version = 0.0;
4842 
4843  public $status_code = 0;
4844 
4845  public $reason = '';
4846 
4847  public $headers = array();
4848 
4849  public $body = '';
4850 
4851  protected $state = 'http_version';
4852 
4853  protected $data = '';
4854 
4855  protected $data_length = 0;
4856 
4857  protected $position = 0;
4858 
4859  protected $name = '';
4860 
4861  protected $value = '';
4862 
4863  public function __construct($data)
4864  {
4865  $this->data = $data;
4866  $this->data_length = strlen($this->data);
4867  }
4868 
4869  public function parse()
4870  {
4871  while ($this->state && $this->state !== 'emit' && $this->has_data())
4872  {
4873  $state = $this->state;
4874  $this->$state();
4875  }
4876  $this->data = '';
4877  if ($this->state === 'emit' || $this->state === 'body')
4878  {
4879  return true;
4880  }
4881  else
4882  {
4883  $this->http_version = '';
4884  $this->status_code = '';
4885  $this->reason = '';
4886  $this->headers = array();
4887  $this->body = '';
4888  return false;
4889  }
4890  }
4891 
4892  protected function has_data()
4893  {
4894  return (bool) ($this->position < $this->data_length);
4895  }
4896 
4897  protected function is_linear_whitespace()
4898  {
4899  return (bool) ($this->data[$this->position] === "\x09"
4900  || $this->data[$this->position] === "\x20"
4901  || ($this->data[$this->position] === "\x0A"
4902  && isset($this->data[$this->position + 1])
4903  && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
4904  }
4905 
4906  protected function http_version()
4907  {
4908  if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
4909  {
4910  $len = strspn($this->data, '0123456789.', 5);
4911  $this->http_version = substr($this->data, 5, $len);
4912  $this->position += 5 + $len;
4913  if (substr_count($this->http_version, '.') <= 1)
4914  {
4915  $this->http_version = (float) $this->http_version;
4916  $this->position += strspn($this->data, "\x09\x20", $this->position);
4917  $this->state = 'status';
4918  }
4919  else
4920  {
4921  $this->state = false;
4922  }
4923  }
4924  else
4925  {
4926  $this->state = false;
4927  }
4928  }
4929 
4930  protected function status()
4931  {
4932  if ($len = strspn($this->data, '0123456789', $this->position))
4933  {
4934  $this->status_code = (int) substr($this->data, $this->position, $len);
4935  $this->position += $len;
4936  $this->state = 'reason';
4937  }
4938  else
4939  {
4940  $this->state = false;
4941  }
4942  }
4943 
4944  protected function reason()
4945  {
4946  $len = strcspn($this->data, "\x0A", $this->position);
4947  $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
4948  $this->position += $len + 1;
4949  $this->state = 'new_line';
4950  }
4951 
4952  protected function new_line()
4953  {
4954  $this->value = trim($this->value, "\x0D\x20");
4955  if ($this->name !== '' && $this->value !== '')
4956  {
4957  $this->name = strtolower($this->name);
4958  // We should only use the last Content-Type header. c.f. issue #1
4959  if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
4960  {
4961  $this->headers[$this->name] .= ', ' . $this->value;
4962  }
4963  else
4964  {
4965  $this->headers[$this->name] = $this->value;
4966  }
4967  }
4968  $this->name = '';
4969  $this->value = '';
4970  if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
4971  {
4972  $this->position += 2;
4973  $this->state = 'body';
4974  }
4975  elseif ($this->data[$this->position] === "\x0A")
4976  {
4977  $this->position++;
4978  $this->state = 'body';
4979  }
4980  else
4981  {
4982  $this->state = 'name';
4983  }
4984  }
4985 
4986  protected function name()
4987  {
4988  $len = strcspn($this->data, "\x0A:", $this->position);
4989  if (isset($this->data[$this->position + $len]))
4990  {
4991  if ($this->data[$this->position + $len] === "\x0A")
4992  {
4993  $this->position += $len;
4994  $this->state = 'new_line';
4995  }
4996  else
4997  {
4998  $this->name = substr($this->data, $this->position, $len);
4999  $this->position += $len + 1;
5000  $this->state = 'value';
5001  }
5002  }
5003  else
5004  {
5005  $this->state = false;
5006  }
5007  }
5008 
5009  protected function linear_whitespace()
5010  {
5011  do
5012  {
5013  if (substr($this->data, $this->position, 2) === "\x0D\x0A")
5014  {
5015  $this->position += 2;
5016  }
5017  elseif ($this->data[$this->position] === "\x0A")
5018  {
5019  $this->position++;
5020  }
5021  $this->position += strspn($this->data, "\x09\x20", $this->position);
5022  } while ($this->has_data() && $this->is_linear_whitespace());
5023  $this->value .= "\x20";
5024  }
5025 
5026  protected function value()
5027  {
5028  if ($this->is_linear_whitespace())
5029  {
5030  $this->linear_whitespace();
5031  }
5032  else
5033  {
5034  switch ($this->data[$this->position])
5035  {
5036  case '"':
5037  // Workaround for ETags: we have to include the quotes as
5038  // part of the tag.
5039  if (strtolower($this->name) === 'etag')
5040  {
5041  $this->value .= '"';
5042  $this->position++;
5043  $this->state = 'value_char';
5044  break;
5045  }
5046  $this->position++;
5047  $this->state = 'quote';
5048  break;
5049  case "\x0A":
5050  $this->position++;
5051  $this->state = 'new_line';
5052  break;
5053  default:
5054  $this->state = 'value_char';
5055  break;
5056  }
5057  }
5058  }
5059 
5060  protected function value_char()
5061  {
5062  $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
5063  $this->value .= substr($this->data, $this->position, $len);
5064  $this->position += $len;
5065  $this->state = 'value';
5066  }
5067 
5068  protected function quote()
5069  {
5070  if ($this->is_linear_whitespace())
5071  {
5072  $this->linear_whitespace();
5073  }
5074  else
5075  {
5076  switch ($this->data[$this->position])
5077  {
5078  case '"':
5079  $this->position++;
5080  $this->state = 'value';
5081  break;
5082  case "\x0A":
5083  $this->position++;
5084  $this->state = 'new_line';
5085  break;
5086  case '\\':
5087  $this->position++;
5088  $this->state = 'quote_escaped';
5089  break;
5090  default:
5091  $this->state = 'quote_char';
5092  break;
5093  }
5094  }
5095  }
5096 
5097  protected function quote_char()
5098  {
5099  $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
5100  $this->value .= substr($this->data, $this->position, $len);
5101  $this->position += $len;
5102  $this->state = 'value';
5103  }
5104 
5105  protected function quote_escaped()
5106  {
5107  $this->value .= $this->data[$this->position];
5108  $this->position++;
5109  $this->state = 'quote';
5110  }
5111 
5112  protected function body()
5113  {
5114  $this->body = substr($this->data, $this->position);
5115  if (!empty($this->headers['transfer-encoding']))
5116  {
5117  unset($this->headers['transfer-encoding']);
5118  $this->state = 'chunked';
5119  }
5120  else
5121  {
5122  $this->state = 'emit';
5123  }
5124  }
5125 
5126  protected function chunked()
5127  {
5128  if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
5129  {
5130  $this->state = 'emit';
5131  return;
5132  }
5133  $decoded = '';
5134  $encoded = $this->body;
5135  while (true)
5136  {
5137  $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
5138  if (!$is_chunked)
5139  {
5140  // Looks like it's not chunked after all
5141  $this->state = 'emit';
5142  return;
5143  }
5144  $length = hexdec(trim($matches[1]));
5145  if ($length === 0)
5146  {
5147  // Ignore trailer headers
5148  $this->state = 'emit';
5149  $this->body = $decoded;
5150  return;
5151  }
5152  $chunk_length = strlen($matches[0]);
5153  $decoded .= $part = substr($encoded, $chunk_length, $length);
5154  $encoded = substr($encoded, $chunk_length + $length + 2);
5155  if (trim($encoded) === '0' || empty($encoded))
5156  {
5157  $this->state = 'emit';
5158  $this->body = $decoded;
5159  return;
5160  }
5161  }
5162  }
5163 }
5165 {
5166 
5167  protected $scheme = null;
5168 
5169  protected $iuserinfo = null;
5170 
5171  protected $ihost = null;
5172 
5173  protected $port = null;
5174 
5175  protected $ipath = '';
5176 
5177  protected $iquery = null;
5178 
5179  protected $ifragment = null;
5180 
5181  protected $normalization = array(
5182  'acap' => array(
5183  'port' => 674
5184  ),
5185  'dict' => array(
5186  'port' => 2628
5187  ),
5188  'file' => array(
5189  'ihost' => 'localhost'
5190  ),
5191  'http' => array(
5192  'port' => 80,
5193  'ipath' => '/'
5194  ),
5195  'https' => array(
5196  'port' => 443,
5197  'ipath' => '/'
5198  ),
5199  );
5200 
5201  public function __toString()
5202  {
5203  return $this->get_iri();
5204  }
5205 
5206  public function __set($name, $value)
5207  {
5208  if (method_exists($this, 'set_' . $name))
5209  {
5210  call_user_func(array($this, 'set_' . $name), $value);
5211  }
5212  elseif (
5213  $name === 'iauthority'
5214  || $name === 'iuserinfo'
5215  || $name === 'ihost'
5216  || $name === 'ipath'
5217  || $name === 'iquery'
5218  || $name === 'ifragment'
5219  )
5220  {
5221  call_user_func(array($this, 'set_' . substr($name, 1)), $value);
5222  }
5223  }
5224 
5225  public function __get($name)
5226  {
5227  // isset() returns false for null, we don't want to do that
5228  // Also why we use array_key_exists below instead of isset()
5229  $props = get_object_vars($this);
5230  if (
5231  $name === 'iri' ||
5232  $name === 'uri' ||
5233  $name === 'iauthority' ||
5234  $name === 'authority'
5235  )
5236  {
5237  $return = $this->{"get_$name"}();
5238  }
5239  elseif (array_key_exists($name, $props))
5240  {
5241  $return = $this->$name;
5242  }
5243  // host -> ihost
5244  elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
5245  {
5246  $name = $prop;
5247  $return = $this->$prop;
5248  }
5249  // ischeme -> scheme
5250  elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
5251  {
5252  $name = $prop;
5253  $return = $this->$prop;
5254  }
5255  else
5256  {
5257  trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
5258  $return = null;
5259  }
5260  if ($return === null && isset($this->normalization[$this->scheme][$name]))
5261  {
5262  return $this->normalization[$this->scheme][$name];
5263  }
5264  else
5265  {
5266  return $return;
5267  }
5268  }
5269 
5270  public function __isset($name)
5271  {
5272  if (method_exists($this, 'get_' . $name) || isset($this->$name))
5273  {
5274  return true;
5275  }
5276  else
5277  {
5278  return false;
5279  }
5280  }
5281 
5282  public function __unset($name)
5283  {
5284  if (method_exists($this, 'set_' . $name))
5285  {
5286  call_user_func(array($this, 'set_' . $name), '');
5287  }
5288  }
5289 
5290  public function __construct($iri = null)
5291  {
5292  $this->set_iri($iri);
5293  }
5294 
5295  public static function absolutize($base, $relative)
5296  {
5297  if (!($relative instanceof SimplePie_IRI))
5298  {
5299  $relative = new SimplePie_IRI($relative);
5300  }
5301  if (!$relative->is_valid())
5302  {
5303  return false;
5304  }
5305  elseif ($relative->scheme !== null)
5306  {
5307  return clone $relative;
5308  }
5309  else
5310  {
5311  if (!($base instanceof SimplePie_IRI))
5312  {
5313  $base = new SimplePie_IRI($base);
5314  }
5315  if ($base->scheme !== null && $base->is_valid())
5316  {
5317  if ($relative->get_iri() !== '')
5318  {
5319  if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
5320  {
5321  $target = clone $relative;
5322  $target->scheme = $base->scheme;
5323  }
5324  else
5325  {
5326  $target = new SimplePie_IRI;
5327  $target->scheme = $base->scheme;
5328  $target->iuserinfo = $base->iuserinfo;
5329  $target->ihost = $base->ihost;
5330  $target->port = $base->port;
5331  if ($relative->ipath !== '')
5332  {
5333  if ($relative->ipath[0] === '/')
5334  {
5335  $target->ipath = $relative->ipath;
5336  }
5337  elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
5338  {
5339  $target->ipath = '/' . $relative->ipath;
5340  }
5341  elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
5342  {
5343  $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
5344  }
5345  else
5346  {
5347  $target->ipath = $relative->ipath;
5348  }
5349  $target->ipath = $target->remove_dot_segments($target->ipath);
5350  $target->iquery = $relative->iquery;
5351  }
5352  else
5353  {
5354  $target->ipath = $base->ipath;
5355  if ($relative->iquery !== null)
5356  {
5357  $target->iquery = $relative->iquery;
5358  }
5359  elseif ($base->iquery !== null)
5360  {
5361  $target->iquery = $base->iquery;
5362  }
5363  }
5364  $target->ifragment = $relative->ifragment;
5365  }
5366  }
5367  else
5368  {
5369  $target = clone $base;
5370  $target->ifragment = null;
5371  }
5372  $target->scheme_normalization();
5373  return $target;
5374  }
5375  else
5376  {
5377  return false;
5378  }
5379  }
5380  }
5381 
5382  protected function parse_iri($iri)
5383  {
5384  $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
5385  if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
5386  {
5387  if ($match[1] === '')
5388  {
5389  $match['scheme'] = null;
5390  }
5391  if (!isset($match[3]) || $match[3] === '')
5392  {
5393  $match['authority'] = null;
5394  }
5395  if (!isset($match[5]))
5396  {
5397  $match['path'] = '';
5398  }
5399  if (!isset($match[6]) || $match[6] === '')
5400  {
5401  $match['query'] = null;
5402  }
5403  if (!isset($match[8]) || $match[8] === '')
5404  {
5405  $match['fragment'] = null;
5406  }
5407  return $match;
5408  }
5409  else
5410  {
5411  // This can occur when a paragraph is accidentally parsed as a URI
5412  return false;
5413  }
5414  }
5415 
5416  protected function remove_dot_segments($input)
5417  {
5418  $output = '';
5419  while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
5420  {
5421  // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
5422  if (strpos($input, '../') === 0)
5423  {
5424  $input = substr($input, 3);
5425  }
5426  elseif (strpos($input, './') === 0)
5427  {
5428  $input = substr($input, 2);
5429  }
5430  // 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,
5431  elseif (strpos($input, '/./') === 0)
5432  {
5433  $input = substr($input, 2);
5434  }
5435  elseif ($input === '/.')
5436  {
5437  $input = '/';
5438  }
5439  // 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,
5440  elseif (strpos($input, '/../') === 0)
5441  {
5442  $input = substr($input, 3);
5443  $output = substr_replace($output, '', strrpos($output, '/'));
5444  }
5445  elseif ($input === '/..')
5446  {
5447  $input = '/';
5448  $output = substr_replace($output, '', strrpos($output, '/'));
5449  }
5450  // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
5451  elseif ($input === '.' || $input === '..')
5452  {
5453  $input = '';
5454  }
5455  // 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
5456  elseif (($pos = strpos($input, '/', 1)) !== false)
5457  {
5458  $output .= substr($input, 0, $pos);
5459  $input = substr_replace($input, '', 0, $pos);
5460  }
5461  else
5462  {
5463  $output .= $input;
5464  $input = '';
5465  }
5466  }
5467  return $output . $input;
5468  }
5469 
5470  protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
5471  {
5472  // Normalize as many pct-encoded sections as possible
5473  $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
5474  // Replace invalid percent characters
5475  $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
5476  // Add unreserved and % to $extra_chars (the latter is safe because all
5477  // pct-encoded sections are now valid).
5478  $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
5479  // Now replace any bytes that aren't allowed with their pct-encoded versions
5480  $position = 0;
5481  $strlen = strlen($string);
5482  while (($position += strspn($string, $extra_chars, $position)) < $strlen)
5483  {
5484  $value = ord($string[$position]);
5485  // Start position
5486  $start = $position;
5487  // By default we are valid
5488  $valid = true;
5489  // No one byte sequences are valid due to the while.
5490  // Two byte sequence:
5491  if (($value & 0xE0) === 0xC0)
5492  {
5493  $character = ($value & 0x1F) << 6;
5494  $length = 2;
5495  $remaining = 1;
5496  }
5497  // Three byte sequence:
5498  elseif (($value & 0xF0) === 0xE0)
5499  {
5500  $character = ($value & 0x0F) << 12;
5501  $length = 3;
5502  $remaining = 2;
5503  }
5504  // Four byte sequence:
5505  elseif (($value & 0xF8) === 0xF0)
5506  {
5507  $character = ($value & 0x07) << 18;
5508  $length = 4;
5509  $remaining = 3;
5510  }
5511  // Invalid byte:
5512  else
5513  {
5514  $valid = false;
5515  $length = 1;
5516  $remaining = 0;
5517  }
5518  if ($remaining)
5519  {
5520  if ($position + $length <= $strlen)
5521  {
5522  for ($position++; $remaining; $position++)
5523  {
5524  $value = ord($string[$position]);
5525  // Check that the byte is valid, then add it to the character:
5526  if (($value & 0xC0) === 0x80)
5527  {
5528  $character |= ($value & 0x3F) << (--$remaining * 6);
5529  }
5530  // If it is invalid, count the sequence as invalid and reprocess the current byte:
5531  else
5532  {
5533  $valid = false;
5534  $position--;
5535  break;
5536  }
5537  }
5538  }
5539  else
5540  {
5541  $position = $strlen - 1;
5542  $valid = false;
5543  }
5544  }
5545  // Percent encode anything invalid or not in ucschar
5546  if (
5547  // Invalid sequences
5548  !$valid
5549  // Non-shortest form sequences are invalid
5550  || $length > 1 && $character <= 0x7F
5551  || $length > 2 && $character <= 0x7FF
5552  || $length > 3 && $character <= 0xFFFF
5553  // Outside of range of ucschar codepoints
5554  // Noncharacters
5555  || ($character & 0xFFFE) === 0xFFFE
5556  || $character >= 0xFDD0 && $character <= 0xFDEF
5557  || (
5558  // Everything else not in ucschar
5559  $character > 0xD7FF && $character < 0xF900
5560  || $character < 0xA0
5561  || $character > 0xEFFFD
5562  )
5563  && (
5564  // Everything not in iprivate, if it applies
5565  !$iprivate
5566  || $character < 0xE000
5567  || $character > 0x10FFFD
5568  )
5569  )
5570  {
5571  // If we were a character, pretend we weren't, but rather an error.
5572  if ($valid)
5573  $position--;
5574  for ($j = $start; $j <= $position; $j++)
5575  {
5576  $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
5577  $j += 2;
5578  $position += 2;
5579  $strlen += 2;
5580  }
5581  }
5582  }
5583  return $string;
5584  }
5585 
5587  {
5588  // As we just have valid percent encoded sequences we can just explode
5589  // and ignore the first member of the returned array (an empty string).
5590  $bytes = explode('%', $match[0]);
5591  // Initialize the new string (this is what will be returned) and that
5592  // there are no bytes remaining in the current sequence (unsurprising
5593  // at the first byte!).
5594  $string = '';
5595  $remaining = 0;
5596  // Loop over each and every byte, and set $value to its value
5597  for ($i = 1, $len = count($bytes); $i < $len; $i++)
5598  {
5599  $value = hexdec($bytes[$i]);
5600  // If we're the first byte of sequence:
5601  if (!$remaining)
5602  {
5603  // Start position
5604  $start = $i;
5605  // By default we are valid
5606  $valid = true;
5607  // One byte sequence:
5608  if ($value <= 0x7F)
5609  {
5610  $character = $value;
5611  $length = 1;
5612  }
5613  // Two byte sequence:
5614  elseif (($value & 0xE0) === 0xC0)
5615  {
5616  $character = ($value & 0x1F) << 6;
5617  $length = 2;
5618  $remaining = 1;
5619  }
5620  // Three byte sequence:
5621  elseif (($value & 0xF0) === 0xE0)
5622  {
5623  $character = ($value & 0x0F) << 12;
5624  $length = 3;
5625  $remaining = 2;
5626  }
5627  // Four byte sequence:
5628  elseif (($value & 0xF8) === 0xF0)
5629  {
5630  $character = ($value & 0x07) << 18;
5631  $length = 4;
5632  $remaining = 3;
5633  }
5634  // Invalid byte:
5635  else
5636  {
5637  $valid = false;
5638  $remaining = 0;
5639  }
5640  }
5641  // Continuation byte:
5642  else
5643  {
5644  // Check that the byte is valid, then add it to the character:
5645  if (($value & 0xC0) === 0x80)
5646  {
5647  $remaining--;
5648  $character |= ($value & 0x3F) << ($remaining * 6);
5649  }
5650  // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
5651  else
5652  {
5653  $valid = false;
5654  $remaining = 0;
5655  $i--;
5656  }
5657  }
5658  // If we've reached the end of the current byte sequence, append it to Unicode::$data
5659  if (!$remaining)
5660  {
5661  // Percent encode anything invalid or not in iunreserved
5662  if (
5663  // Invalid sequences
5664  !$valid
5665  // Non-shortest form sequences are invalid
5666  || $length > 1 && $character <= 0x7F
5667  || $length > 2 && $character <= 0x7FF
5668  || $length > 3 && $character <= 0xFFFF
5669  // Outside of range of iunreserved codepoints
5670  || $character < 0x2D
5671  || $character > 0xEFFFD
5672  // Noncharacters
5673  || ($character & 0xFFFE) === 0xFFFE
5674  || $character >= 0xFDD0 && $character <= 0xFDEF
5675  // Everything else not in iunreserved (this is all BMP)
5676  || $character === 0x2F
5677  || $character > 0x39 && $character < 0x41
5678  || $character > 0x5A && $character < 0x61
5679  || $character > 0x7A && $character < 0x7E
5680  || $character > 0x7E && $character < 0xA0
5681  || $character > 0xD7FF && $character < 0xF900
5682  )
5683  {
5684  for ($j = $start; $j <= $i; $j++)
5685  {
5686  $string .= '%' . strtoupper($bytes[$j]);
5687  }
5688  }
5689  else
5690  {
5691  for ($j = $start; $j <= $i; $j++)
5692  {
5693  $string .= chr(hexdec($bytes[$j]));
5694  }
5695  }
5696  }
5697  }
5698  // If we have any bytes left over they are invalid (i.e., we are
5699  // mid-way through a multi-byte sequence)
5700  if ($remaining)
5701  {
5702  for ($j = $start; $j < $len; $j++)
5703  {
5704  $string .= '%' . strtoupper($bytes[$j]);
5705  }
5706  }
5707  return $string;
5708  }
5709  protected function scheme_normalization()
5710  {
5711  if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
5712  {
5713  $this->iuserinfo = null;
5714  }
5715  if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
5716  {
5717  $this->ihost = null;
5718  }
5719  if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
5720  {
5721  $this->port = null;
5722  }
5723  if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
5724  {
5725  $this->ipath = '';
5726  }
5727  if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
5728  {
5729  $this->iquery = null;
5730  }
5731  if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
5732  {