summaryrefslogtreecommitdiff
path: root/vendor/miniflux/picofeed/lib/PicoFeed/Reader
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2017-10-25 16:22:10 -0700
committerFrederic Guillot <fred@kanboard.net>2017-10-25 16:22:10 -0700
commit9e2b2a32fd0e967ad3184e9a5d091a29953acb91 (patch)
tree00822e24aa1110c73ca455a8d096ef296c008cbc /vendor/miniflux/picofeed/lib/PicoFeed/Reader
parentc507c5416251c505cb3e088a03c6664bed73c812 (diff)
Include composer dependencies in repo
Diffstat (limited to 'vendor/miniflux/picofeed/lib/PicoFeed/Reader')
-rw-r--r--vendor/miniflux/picofeed/lib/PicoFeed/Reader/Favicon.php186
-rw-r--r--vendor/miniflux/picofeed/lib/PicoFeed/Reader/Reader.php190
-rw-r--r--vendor/miniflux/picofeed/lib/PicoFeed/Reader/ReaderException.php14
-rw-r--r--vendor/miniflux/picofeed/lib/PicoFeed/Reader/SubscriptionNotFoundException.php12
-rw-r--r--vendor/miniflux/picofeed/lib/PicoFeed/Reader/UnsupportedFeedFormatException.php12
5 files changed, 414 insertions, 0 deletions
diff --git a/vendor/miniflux/picofeed/lib/PicoFeed/Reader/Favicon.php b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/Favicon.php
new file mode 100644
index 00000000..d4ca07db
--- /dev/null
+++ b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/Favicon.php
@@ -0,0 +1,186 @@
+<?php
+
+namespace PicoFeed\Reader;
+
+use DOMXPath;
+use PicoFeed\Base;
+use PicoFeed\Client\Client;
+use PicoFeed\Client\ClientException;
+use PicoFeed\Client\Url;
+use PicoFeed\Logging\Logger;
+use PicoFeed\Parser\XmlParser;
+
+/**
+ * Favicon class.
+ *
+ * https://en.wikipedia.org/wiki/Favicon
+ *
+ * @author Frederic Guillot
+ */
+class Favicon extends Base
+{
+ /**
+ * Valid types for favicon (supported by browsers).
+ *
+ * @var array
+ */
+ private $types = array(
+ 'image/png',
+ 'image/gif',
+ 'image/x-icon',
+ 'image/jpeg',
+ 'image/jpg',
+ 'image/svg+xml',
+ );
+
+ /**
+ * Icon binary content.
+ *
+ * @var string
+ */
+ private $content = '';
+
+ /**
+ * Icon content type.
+ *
+ * @var string
+ */
+ private $content_type = '';
+
+ /**
+ * Get the icon file content (available only after the download).
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ /**
+ * Get the icon file type (available only after the download).
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ foreach ($this->types as $type) {
+ if (strpos($this->content_type, $type) === 0) {
+ return $type;
+ }
+ }
+
+ return 'image/x-icon';
+ }
+
+ /**
+ * Get data URI (http://en.wikipedia.org/wiki/Data_URI_scheme).
+ *
+ * @return string
+ */
+ public function getDataUri()
+ {
+ if (empty($this->content)) {
+ return '';
+ }
+
+ return sprintf(
+ 'data:%s;base64,%s',
+ $this->getType(),
+ base64_encode($this->content)
+ );
+ }
+
+ /**
+ * Download and check if a resource exists.
+ *
+ * @param string $url URL
+ * @return \PicoFeed\Client\Client Client instance
+ */
+ public function download($url)
+ {
+ $client = Client::getInstance();
+ $client->setConfig($this->config);
+
+ Logger::setMessage(get_called_class().' Download => '.$url);
+
+ try {
+ $client->execute($url);
+ } catch (ClientException $e) {
+ Logger::setMessage(get_called_class().' Download Failed => '.$e->getMessage());
+ }
+
+ return $client;
+ }
+
+ /**
+ * Check if a remote file exists.
+ *
+ * @param string $url URL
+ * @return bool
+ */
+ public function exists($url)
+ {
+ return $this->download($url)->getContent() !== '';
+ }
+
+ /**
+ * Get the icon link for a website.
+ *
+ * @param string $website_link URL
+ * @param string $favicon_link optional URL
+ * @return string
+ */
+ public function find($website_link, $favicon_link = '')
+ {
+ $website = new Url($website_link);
+
+ if ($favicon_link !== '') {
+ $icons = array($favicon_link);
+ } else {
+ $icons = $this->extract($this->download($website->getBaseUrl('/'))->getContent());
+ $icons[] = $website->getBaseUrl('/favicon.ico');
+ }
+
+ foreach ($icons as $icon_link) {
+ $icon_link = Url::resolve($icon_link, $website);
+ $resource = $this->download($icon_link);
+ $this->content = $resource->getContent();
+ $this->content_type = $resource->getContentType();
+
+ if ($this->content !== '') {
+ return $icon_link;
+ } elseif ($favicon_link !== '') {
+ return $this->find($website_link);
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Extract the icon links from the HTML.
+ *
+ * @param string $html HTML
+ * @return array
+ */
+ public function extract($html)
+ {
+ $icons = array();
+
+ if (empty($html)) {
+ return $icons;
+ }
+
+ $dom = XmlParser::getHtmlDocument($html);
+
+ $xpath = new DOMXpath($dom);
+ $elements = $xpath->query('//link[@rel="icon" or @rel="shortcut icon" or @rel="Shortcut Icon" or @rel="icon shortcut"]');
+
+ for ($i = 0; $i < $elements->length; ++$i) {
+ $icons[] = $elements->item($i)->getAttribute('href');
+ }
+
+ return $icons;
+ }
+}
diff --git a/vendor/miniflux/picofeed/lib/PicoFeed/Reader/Reader.php b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/Reader.php
new file mode 100644
index 00000000..769ffe93
--- /dev/null
+++ b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/Reader.php
@@ -0,0 +1,190 @@
+<?php
+
+namespace PicoFeed\Reader;
+
+use DOMXPath;
+use PicoFeed\Base;
+use PicoFeed\Client\Client;
+use PicoFeed\Client\Url;
+use PicoFeed\Logging\Logger;
+use PicoFeed\Parser\XmlParser;
+
+/**
+ * Reader class.
+ *
+ * @author Frederic Guillot
+ */
+class Reader extends Base
+{
+ /**
+ * Feed formats for detection.
+ *
+ * @var array
+ */
+ private $formats = array(
+ 'Atom' => '//feed',
+ 'Rss20' => '//rss[@version="2.0"]',
+ 'Rss92' => '//rss[@version="0.92"]',
+ 'Rss91' => '//rss[@version="0.91"]',
+ 'Rss10' => '//rdf',
+ );
+
+ /**
+ * Download a feed (no discovery).
+ *
+ * @param string $url Feed url
+ * @param string $last_modified Last modified HTTP header
+ * @param string $etag Etag HTTP header
+ * @param string $username HTTP basic auth username
+ * @param string $password HTTP basic auth password
+ *
+ * @return \PicoFeed\Client\Client
+ */
+ public function download($url, $last_modified = '', $etag = '', $username = '', $password = '')
+ {
+ $url = $this->prependScheme($url);
+
+ return Client::getInstance()
+ ->setConfig($this->config)
+ ->setLastModified($last_modified)
+ ->setEtag($etag)
+ ->setUsername($username)
+ ->setPassword($password)
+ ->execute($url);
+ }
+
+ /**
+ * Discover and download a feed.
+ *
+ * @param string $url Feed or website url
+ * @param string $last_modified Last modified HTTP header
+ * @param string $etag Etag HTTP header
+ * @param string $username HTTP basic auth username
+ * @param string $password HTTP basic auth password
+ * @return Client
+ * @throws SubscriptionNotFoundException
+ */
+ public function discover($url, $last_modified = '', $etag = '', $username = '', $password = '')
+ {
+ $client = $this->download($url, $last_modified, $etag, $username, $password);
+
+ // It's already a feed or the feed was not modified
+ if (!$client->isModified() || $this->detectFormat($client->getContent())) {
+ return $client;
+ }
+
+ // Try to find a subscription
+ $links = $this->find($client->getUrl(), $client->getContent());
+
+ if (empty($links)) {
+ throw new SubscriptionNotFoundException('Unable to find a subscription');
+ }
+
+ return $this->download($links[0], $last_modified, $etag, $username, $password);
+ }
+
+ /**
+ * Find feed urls inside a HTML document.
+ *
+ * @param string $url Website url
+ * @param string $html HTML content
+ *
+ * @return array List of feed links
+ */
+ public function find($url, $html)
+ {
+ Logger::setMessage(get_called_class().': Try to discover subscriptions');
+
+ $dom = XmlParser::getHtmlDocument($html);
+ $xpath = new DOMXPath($dom);
+ $links = array();
+
+ $queries = array(
+ '//link[@type="application/rss+xml"]',
+ '//link[@type="application/atom+xml"]',
+ );
+
+ foreach ($queries as $query) {
+ $nodes = $xpath->query($query);
+
+ foreach ($nodes as $node) {
+ $link = $node->getAttribute('href');
+
+ if (!empty($link)) {
+ $feedUrl = new Url($link);
+ $siteUrl = new Url($url);
+
+ $links[] = $feedUrl->getAbsoluteUrl($feedUrl->isRelativeUrl() ? $siteUrl->getBaseUrl() : '');
+ }
+ }
+ }
+
+ Logger::setMessage(get_called_class().': '.implode(', ', $links));
+
+ return $links;
+ }
+
+ /**
+ * Get a parser instance.
+ *
+ * @param string $url Site url
+ * @param string $content Feed content
+ * @param string $encoding HTTP encoding
+ *
+ * @return \PicoFeed\Parser\Parser
+ */
+ public function getParser($url, $content, $encoding)
+ {
+ $format = $this->detectFormat($content);
+
+ if (empty($format)) {
+ throw new UnsupportedFeedFormatException('Unable to detect feed format');
+ }
+
+ $className = '\PicoFeed\Parser\\'.$format;
+
+ $parser = new $className($content, $encoding, $url);
+ $parser->setHashAlgo($this->config->getParserHashAlgo());
+ $parser->setConfig($this->config);
+
+ return $parser;
+ }
+
+ /**
+ * Detect the feed format.
+ *
+ * @param string $content Feed content
+ *
+ * @return string
+ */
+ public function detectFormat($content)
+ {
+ $dom = XmlParser::getHtmlDocument($content);
+ $xpath = new DOMXPath($dom);
+
+ foreach ($this->formats as $parser_name => $query) {
+ $nodes = $xpath->query($query);
+
+ if ($nodes->length === 1) {
+ return $parser_name;
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Add the prefix "http://" if the end-user just enter a domain name.
+ *
+ * @param string $url Url
+ * @retunr string
+ */
+ public function prependScheme($url)
+ {
+ if (!preg_match('%^https?://%', $url)) {
+ $url = 'http://'.$url;
+ }
+
+ return $url;
+ }
+}
diff --git a/vendor/miniflux/picofeed/lib/PicoFeed/Reader/ReaderException.php b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/ReaderException.php
new file mode 100644
index 00000000..4f03dbe0
--- /dev/null
+++ b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/ReaderException.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace PicoFeed\Reader;
+
+use PicoFeed\PicoFeedException;
+
+/**
+ * ReaderException Exception.
+ *
+ * @author Frederic Guillot
+ */
+abstract class ReaderException extends PicoFeedException
+{
+}
diff --git a/vendor/miniflux/picofeed/lib/PicoFeed/Reader/SubscriptionNotFoundException.php b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/SubscriptionNotFoundException.php
new file mode 100644
index 00000000..dd77847e
--- /dev/null
+++ b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/SubscriptionNotFoundException.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace PicoFeed\Reader;
+
+/**
+ * SubscriptionNotFoundException Exception.
+ *
+ * @author Frederic Guillot
+ */
+class SubscriptionNotFoundException extends ReaderException
+{
+}
diff --git a/vendor/miniflux/picofeed/lib/PicoFeed/Reader/UnsupportedFeedFormatException.php b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/UnsupportedFeedFormatException.php
new file mode 100644
index 00000000..4aa8d87f
--- /dev/null
+++ b/vendor/miniflux/picofeed/lib/PicoFeed/Reader/UnsupportedFeedFormatException.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace PicoFeed\Reader;
+
+/**
+ * UnsupportedFeedFormatException Exception.
+ *
+ * @author Frederic Guillot
+ */
+class UnsupportedFeedFormatException extends ReaderException
+{
+}