?
* public function get(string $key, mixed $default = null): mixed; *
* public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool; *
* public function delete(string $key): bool; *
'; for ($j = 0; $j < $count; $j++) { $hidden = $j === 0 ? '' : 'class="hidden" '; $description .= ''. ''; } $description .= ''.$count.' photos
'. ''.$in_reply_to.'
'; } } $item['description'] = [['data' => $description]]; } if (isset($entry['properties']['category'])) { $category_csv = ''; // Categories can also contain h-cards. foreach ($entry['properties']['category'] as $category) { if ($category_csv !== '') { $category_csv .= ', '; } if (is_string($category)) { // Can't have commas in categories. $category_csv .= str_replace(',', '', $category); } else { $category_csv .= $this->parse_hcard($category, true); } } $item['category'] = [['data' => $category_csv]]; } if (isset($entry['properties']['published'][0])) { $timestamp = strtotime($entry['properties']['published'][0]); $pub_date = date('F j Y g:ia', $timestamp).' GMT'; $item['pubDate'] = [['data' => $pub_date]]; } // The title and description are set to the empty string to represent // a deleted item (which also makes it an invalid rss item). if (isset($entry['properties']['deleted'][0])) { $item['title'] = [['data' => '']]; $item['description'] = [['data' => '']]; } $items[] = ['child' => ['' => $item]]; } } // Mimic RSS data format when storing microformats. $link = [['data' => $url]]; $image = ''; if (!is_string($feed_author) && isset($feed_author['properties']['photo'][0])) { $image = [['child' => ['' => ['url' => [['data' => $feed_author['properties']['photo'][0]]]]]]]; } // Use the name given for the h-feed, or get the title from the html. if ($feed_title !== '') { $feed_title = [['data' => htmlspecialchars($feed_title)]]; } elseif ($position = strpos($data, '
* // This is probably a bad example because we already support * // natively, but it shows you how to parse through * // the nodes. * $group = $item->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'group'); * $content = $group[0]['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['content']; * $file = $content[0]['attribs']['']['url']; * echo $file; *
"?)' . preg_quote($rel) . '(?P=quote)\s*(?=,|$)/i', $link_headers, $matches)) { return $matches['uri']; } } if (isset($this->data['links'][$rel])) { return $this->data['links'][$rel]; } return null; } public function get_all_discovered_feeds() { return $this->all_discovered_feeds; } /** * Get the content for the item * * Uses ``, ``, ``, * ``, `` or `` * * @since 1.0 (previously called `get_feed_description()` since 0.8) * @return string|null */ public function get_description() { if ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'subtitle')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'tagline')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_10, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_090, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_11, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_10, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ITUNES, 'summary')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ITUNES, 'subtitle')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_HTML, $this->get_base($return[0])); } return null; } /** * Get the copyright info for the feed * * Uses ``, `` or `` * * @since 1.0 (previously called `get_feed_copyright()` since 0.8) * @return string|null */ public function get_copyright() { if ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'rights')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'copyright')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'copyright')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_11, 'rights')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_10, 'rights')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } return null; } /** * Get the language for the feed * * Uses ``, ``, or @xml_lang * * @since 1.0 (previously called `get_feed_language()` since 0.8) * @return string|null */ public function get_language() { if ($return = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'language')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_11, 'language')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_10, 'language')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['child'][self::NAMESPACE_ATOM_10]['feed'][0]['xml_lang'])) { return $this->sanitize($this->data['child'][self::NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['child'][self::NAMESPACE_ATOM_03]['feed'][0]['xml_lang'])) { return $this->sanitize($this->data['child'][self::NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['xml_lang'])) { return $this->sanitize($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['xml_lang'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['headers']['content-language'])) { return $this->sanitize($this->data['headers']['content-language'], self::CONSTRUCT_TEXT); } return null; } /** * Get the latitude coordinates for the item * * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications * * Uses `` or `` * * @since 1.0 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo * @link http://www.georss.org/ GeoRSS * @return string|null */ public function get_latitude() { if ($return = $this->get_channel_tags(self::NAMESPACE_W3C_BASIC_GEO, 'lat')) { 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[1]; } return null; } /** * Get the longitude coordinates for the feed * * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications * * Uses ``, `` or `` * * @since 1.0 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo * @link http://www.georss.org/ GeoRSS * @return string|null */ 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]; } return null; } /** * 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 `` or `` * * @return string|null */ 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); } return null; } /** * 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 ``, ``, ``, * `` or `` * * @return string|null */ 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])); } return null; } /** * 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 ``, ``, ``, * `` or `` * * @return string|null */ 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])); } return null; } /** * Get the feed logo's link * * RSS 2.0 feeds are allowed to have a "feed logo" width. * * Uses `` or defaults to 88 if no width is specified and * the feed is an RSS 2.0 feed. * * @return int|null */ 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')) { return 88; } return null; } /** * Get the feed logo's height * * RSS 2.0 feeds are allowed to have a "feed logo" height. * * Uses `` or defaults to 31 if no height is specified and * the feed is an RSS 2.0 feed. * * @return int|null */ 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')) { return 31; } return null; } /** * Get the number of items in the feed * * This is well-suited for {@link http://php.net/for for()} loops with * {@see get_item()} * * @param int $max Maximum value to return. 0 for no limit * @return int Number of items in the feed */ public function get_item_quantity($max = 0) { $max = (int) $max; $qty = count($this->get_items()); if ($max === 0) { return $qty; } return ($qty > $max) ? $max : $qty; } /** * 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() * @since Beta 2 * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Item|null */ public function get_item($key = 0) { $items = $this->get_items(); if (isset($items[$key])) { return $items[$key]; } return null; } /** * 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. * * @see get_item_quantity * @since Beta 2 * @param int $start Index to start at * @param int $end Number of items to return. 0 for all items after `$start` * @return \SimplePie\Item[]|null List of {@see \SimplePie\Item} objects */ public function get_items($start = 0, $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 []; } 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->registry->create(Item::class, [$this, $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->registry->create(Item::class, [$this, $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->registry->create(Item::class, [$this, $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->registry->create(Item::class, [$this, $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->registry->create(Item::class, [$this, $items[$key]]); } } } if (empty($this->data['items'])) { return []; } 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']; } else { $items = $this->data['items']; } // Slice the data as desired if ($end === 0) { return array_slice($items, $start); } return array_slice($items, $start, $end); } /** * Set the favicon handler * * @deprecated Use your own favicon handling instead */ public function set_favicon_handler($page = false, $qs = 'i') { trigger_error('Favicon handling has been removed, please use your own handling', \E_USER_DEPRECATED); return false; } /** * 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, please use your own handling', \E_USER_DEPRECATED); if (($url = $this->get_link()) !== null) { return 'https://www.google.com/s2/favicons?domain=' . urlencode($url); } return false; } /** * Magic method handler * * @param string $method Method name * @param array $args Arguments to the method * @return mixed */ public function __call($method, $args) { if (strpos($method, 'subscribe_') === 0) { trigger_error('subscribe_*() has been deprecated, implement the callback yourself', \E_USER_DEPRECATED); return ''; } if ($method === 'enable_xml_dump') { trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', \E_USER_DEPRECATED); return false; } $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"); } /** * Sorting callback for items * * @access private * @param SimplePie $a * @param SimplePie $b * @return boolean */ public static function sort_items($a, $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. if ($a_date) { return 1; } if ($b_date) { return -1; } return 0; } /** * 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 $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 * @return array */ public static function merge_items($urls, $start = 0, $end = 0, $limit = 0) { if (is_array($urls) && sizeof($urls) > 0) { $items = []; foreach ($urls as $arg) { if ($arg instanceof SimplePie) { $items = array_merge($items, $arg->get_items(0, $limit)); } else { trigger_error('Arguments must be SimplePie objects', E_USER_WARNING); } } usort($items, [get_class($urls[0]), 'sort_items']); if ($end === 0) { return array_slice($items, $start); } return array_slice($items, $start, $end); } trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING); return []; } /** * 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. * @param \SimplePie\File $file * @param string $hub * @param string $self */ private function store_links(&$file, $hub, $self) { if (isset($file->headers['link']['hub']) || (isset($file->headers['link']) && preg_match('/rel=hub/', $file->headers['link']))) { return; } if ($hub) { if (isset($file->headers['link'])) { if ($file->headers['link'] !== '') { $file->headers['link'] = ', '; } } else { $file->headers['link'] = ''; } $file->headers['link'] .= '<'.$hub.'>; rel=hub'; if ($self) { $file->headers['link'] .= ', <'.$self.'>; rel=self'; } } } /** * Get a DataCache * * @param string $feed_url Only needed for BC, can be removed in SimplePie 2.0.0 * * @return DataCache */ private function get_cache($feed_url = '') { 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->cache_location, $this->get_cache_filename($feed_url), Base::TYPE_FEED ]); return new BaseDataCache($cache); } return $this->cache; } } class_alias('SimplePie\SimplePie', 'SimplePie'); src/Content/Type/Sniffer.php 0000644 00000022112 15000652215 0011765 0 ustar 00 file = $file; } /** * Get the Content-Type of the specified file * * @return string Actual Content-Type */ public function get_type() { if (isset($this->file->headers['content-type'])) { if (!isset($this->file->headers['content-encoding']) && ($this->file->headers['content-type'] === 'text/plain' || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1' || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1' || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8')) { return $this->text_or_binary(); } if (($pos = strpos($this->file->headers['content-type'], ';')) !== false) { $official = substr($this->file->headers['content-type'], 0, $pos); } else { $official = $this->file->headers['content-type']; } $official = trim(strtolower($official)); if ($official === 'unknown/unknown' || $official === 'application/unknown') { return $this->unknown(); } elseif (substr($official, -4) === '+xml' || $official === 'text/xml' || $official === 'application/xml') { return $official; } elseif (substr($official, 0, 6) === 'image/') { if ($return = $this->image()) { return $return; } return $official; } elseif ($official === 'text/html') { return $this->feed_or_html(); } return $official; } return $this->unknown(); } /** * Sniff text or binary * * @return string Actual Content-Type */ public function text_or_binary() { if (substr($this->file->body, 0, 2) === "\xFE\xFF" || substr($this->file->body, 0, 2) === "\xFF\xFE" || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF" || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF") { return 'text/plain'; } elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body)) { return 'application/octet-stream'; } return 'text/plain'; } /** * Sniff unknown * * @return string Actual Content-Type */ public function unknown() { $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20"); if (strtolower(substr($this->file->body, $ws, 14)) === 'file->body, $ws, 5)) === 'file->body, $ws, 7)) === '