* @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
* @link http://www.georss.org/ GeoRSS
public function get_longitude()
if ($return = $this->get_channel_tags(self::NAMESPACE_W3C_BASIC_GEO, 'long')) {
return (float) $return[0]['data'];
} elseif ($return = $this->get_channel_tags(self::NAMESPACE_W3C_BASIC_GEO, 'lon')) {
return (float) $return[0]['data'];
} elseif (($return = $this->get_channel_tags(self::NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) {
return (float) $match[2];
* Get the feed logo's title
* RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
* Uses `<image><title>` or `<image><dc:title>`
public function get_image_title()
if ($return = $this->get_image_tags(self::NAMESPACE_RSS_10, 'title')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT);
} elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_090, 'title')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT);
} elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'title')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT);
} elseif ($return = $this->get_image_tags(self::NAMESPACE_DC_11, 'title')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT);
} elseif ($return = $this->get_image_tags(self::NAMESPACE_DC_10, 'title')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT);
* Get the feed logo's URL
* RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
* have a "feed logo" URL. This points directly to the image itself.
* Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
* `<image><title>` or `<image><dc:title>`
public function get_image_url()
if ($return = $this->get_channel_tags(self::NAMESPACE_ITUNES, 'image')) {
return $this->sanitize($return[0]['attribs']['']['href'], self::CONSTRUCT_IRI);
} elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'logo')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
} elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'icon')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
} elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_10, 'url')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
} elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_090, 'url')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
} elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'url')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
* Get the feed logo's link
* RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
* points to a human-readable page that the image should link to.
* Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
* `<image><title>` or `<image><dc:title>`
public function get_image_link()
if ($return = $this->get_image_tags(self::NAMESPACE_RSS_10, 'link')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
} elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_090, 'link')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
} elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'link')) {
return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0]));
* Get the feed logo's link
* RSS 2.0 feeds are allowed to have a "feed logo" width.
* Uses `<image><width>` or defaults to 88 if no width is specified and
* the feed is an RSS 2.0 feed.
public function get_image_width()
if ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'width')) {
return intval($return[0]['data']);
} elseif ($this->get_type() & self::TYPE_RSS_SYNDICATION && $this->get_image_tags(self::NAMESPACE_RSS_20, 'url')) {
* Get the feed logo's height
* RSS 2.0 feeds are allowed to have a "feed logo" height.
* Uses `<image><height>` or defaults to 31 if no height is specified and
* the feed is an RSS 2.0 feed.
public function get_image_height()
if ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'height')) {
return intval($return[0]['data']);
} elseif ($this->get_type() & self::TYPE_RSS_SYNDICATION && $this->get_image_tags(self::NAMESPACE_RSS_20, 'url')) {
* Get the number of items in the feed
* This is well-suited for {@link http://php.net/for for()} loops with
* @param int $max Maximum value to return. 0 for no limit
* @return int Number of items in the feed
public function get_item_quantity(int $max = 0)
$qty = count($this->get_items());
* Get a single item from the feed
* This is better suited for {@link http://php.net/for for()} loops, whereas
* {@see get_items()} is better suited for
* {@link http://php.net/foreach foreach()} loops.
* @see get_item_quantity()
* @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
public function get_item(int $key = 0)
$items = $this->get_items();
if (isset($items[$key])) {
* Get all items from the feed
* This is better suited for {@link http://php.net/for for()} loops, whereas
* {@see get_items()} is better suited for
* {@link http://php.net/foreach foreach()} loops.
* @param int $start Index to start at
* @param int $end Number of items to return. 0 for all items after `$start`
* @return Item[] List of {@see Item} objects
public function get_items(int $start = 0, int $end = 0)
if (!isset($this->data['items'])) {
if (!empty($this->multifeed_objects)) {
$this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
if (empty($this->data['items'])) {
return $this->data['items'];
$this->data['items'] = [];
if ($items = $this->get_feed_tags(self::NAMESPACE_ATOM_10, 'entry')) {
$keys = array_keys($items);
foreach ($keys as $key) {
$this->data['items'][] = $this->make_item($items[$key]);
if ($items = $this->get_feed_tags(self::NAMESPACE_ATOM_03, 'entry')) {
$keys = array_keys($items);
foreach ($keys as $key) {
$this->data['items'][] = $this->make_item($items[$key]);
if ($items = $this->get_feed_tags(self::NAMESPACE_RSS_10, 'item')) {
$keys = array_keys($items);
foreach ($keys as $key) {
$this->data['items'][] = $this->make_item($items[$key]);
if ($items = $this->get_feed_tags(self::NAMESPACE_RSS_090, 'item')) {
$keys = array_keys($items);
foreach ($keys as $key) {
$this->data['items'][] = $this->make_item($items[$key]);
if ($items = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'item')) {
$keys = array_keys($items);
foreach ($keys as $key) {
$this->data['items'][] = $this->make_item($items[$key]);
if (empty($this->data['items'])) {
if ($this->order_by_date) {
if (!isset($this->data['ordered_items'])) {
$this->data['ordered_items'] = $this->data['items'];
usort($this->data['ordered_items'], [get_class($this), 'sort_items']);
$items = $this->data['ordered_items'];
$items = $this->data['items'];
// Slice the data as desired
return array_slice($items, $start);
return array_slice($items, $start, $end);
* Set the favicon handler
* @deprecated Use your own favicon handling instead
* @param string|false $page
public function set_favicon_handler($page = false, string $qs = 'i')
trigger_error('Favicon handling has been removed since SimplePie 1.3, please use your own handling', \E_USER_DEPRECATED);
* Get the favicon for the current feed
* @deprecated Use your own favicon handling instead
public function get_favicon()
trigger_error('Favicon handling has been removed since SimplePie 1.3, please use your own handling', \E_USER_DEPRECATED);
if (($url = $this->get_link()) !== null) {
return 'https://www.google.com/s2/favicons?domain=' . urlencode($url);
* @param string $method Method name
* @param array<mixed> $args Arguments to the method
public function __call(string $method, array $args)
if (strpos($method, 'subscribe_') === 0) {
trigger_error('subscribe_*() has been deprecated since SimplePie 1.3, implement the callback yourself', \E_USER_DEPRECATED);
if ($method === 'enable_xml_dump') {
trigger_error('enable_xml_dump() has been deprecated since SimplePie 1.3, use get_raw_data() instead', \E_USER_DEPRECATED);
$class = get_class($this);
$trace = debug_backtrace(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
$file = $trace[0]['file'] ?? '';
$line = $trace[0]['line'] ?? '';
throw new SimplePieException("Call to undefined method $class::$method() in $file on line $line");
* @param array<string, mixed> $data
private function make_item(array $data): Item
$item = $this->registry->create(Item::class, [$this, $data]);
$item->set_sanitize($this->sanitize);
* Sorting callback for items
public static function sort_items(Item $a, Item $b)
$a_date = $a->get_date('U');
$b_date = $b->get_date('U');
if ($a_date && $b_date) {
return $a_date > $b_date ? -1 : 1;
// Sort items without dates to the top.
* Merge items from several feeds into one
* If you're merging multiple feeds together, they need to all have dates
* for the items or else SimplePie will refuse to sort them.
* @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
* @param array<SimplePie> $urls List of SimplePie feed objects to merge
* @param int $start Starting item
* @param int $end Number of items to return
* @param int $limit Maximum number of items per feed
public static function merge_items(array $urls, int $start = 0, int $end = 0, int $limit = 0)
foreach ($urls as $arg) {
if ($arg instanceof SimplePie) {
$items = array_merge($items, $arg->get_items(0, $limit));
// @phpstan-ignore-next-line Enforce PHPDoc type.
trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
usort($items, [get_class($urls[0]), 'sort_items']);
return array_slice($items, $start);
return array_slice($items, $start, $end);
trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
* Store PubSubHubbub links as headers
* There is no way to find PuSH links in the body of a microformats feed,
* so they are added to the headers when found, to be used later by get_links.
private function store_links(Response $file, ?string $hub, ?string $self): Response
$linkHeaderLine = $file->get_header_line('link');
$linkHeader = $file->get_header('link');
if ($hub && !preg_match('/rel=hub/', $linkHeaderLine)) {
$linkHeader[] = '<'.$hub.'>; rel=hub';
if ($self && !preg_match('/rel=self/', $linkHeaderLine)) {
$linkHeader[] = '<'.$self.'>; rel=self';
if (count($linkHeader) > 0) {
$file = $file->with_header('link', $linkHeader);
* @param string $feed_url Only needed for BC, can be removed in SimplePie 2.0.0
private function get_cache(string $feed_url = ''): DataCache
if ($this->cache === null) {
// @trigger_error(sprintf('Not providing as PSR-16 cache implementation is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache()".'), \E_USER_DEPRECATED);
$cache = $this->registry->call(Cache::class, 'get_handler', [
$this->get_cache_filename($feed_url),
return new BaseDataCache($cache);
private function get_http_client(): Client
if ($this->http_client === null) {
$this->http_client = new FileClient(
'timeout' => $this->timeout,
'useragent' => $this->useragent,
'force_fsockopen' => $this->force_fsockopen,
'curl_options' => $this->curl_options,
$this->http_client_injected = true;
return $this->http_client;
class_alias('SimplePie\SimplePie', 'SimplePie');