2014-10-19 20:42:31 +02:00
|
|
|
<?php
|
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
namespace PicoFeed\Reader;
|
2014-10-19 20:42:31 +02:00
|
|
|
|
2016-03-24 22:49:50 +01:00
|
|
|
use DOMXPath;
|
|
|
|
use PicoFeed\Base;
|
2014-12-24 03:28:26 +01:00
|
|
|
use PicoFeed\Client\Client;
|
|
|
|
use PicoFeed\Client\ClientException;
|
|
|
|
use PicoFeed\Client\Url;
|
|
|
|
use PicoFeed\Logging\Logger;
|
|
|
|
use PicoFeed\Parser\XmlParser;
|
2014-10-19 20:42:31 +02:00
|
|
|
|
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Favicon class.
|
2014-10-19 20:42:31 +02:00
|
|
|
*
|
|
|
|
* https://en.wikipedia.org/wiki/Favicon
|
|
|
|
*
|
|
|
|
* @author Frederic Guillot
|
|
|
|
*/
|
2016-03-24 22:49:50 +01:00
|
|
|
class Favicon extends Base
|
2014-10-19 20:42:31 +02:00
|
|
|
{
|
2014-12-24 23:54:27 +01:00
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Valid types for favicon (supported by browsers).
|
2014-12-24 23:54:27 +01:00
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private $types = array(
|
|
|
|
'image/png',
|
|
|
|
'image/gif',
|
|
|
|
'image/x-icon',
|
|
|
|
'image/jpeg',
|
|
|
|
'image/jpg',
|
2016-01-12 02:03:13 +01:00
|
|
|
'image/svg+xml'
|
2014-12-24 23:54:27 +01:00
|
|
|
);
|
|
|
|
|
2014-10-19 20:42:31 +02:00
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Icon binary content.
|
2014-10-19 20:42:31 +02:00
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
private $content = '';
|
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Icon content type.
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
private $content_type = '';
|
|
|
|
|
2014-10-19 20:42:31 +02:00
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Get the icon file content (available only after the download).
|
2014-10-19 20:42:31 +02:00
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getContent()
|
|
|
|
{
|
|
|
|
return $this->content;
|
|
|
|
}
|
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Get the icon file type (available only after the download).
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getType()
|
|
|
|
{
|
2014-12-24 23:54:27 +01:00
|
|
|
foreach ($this->types as $type) {
|
|
|
|
if (strpos($this->content_type, $type) === 0) {
|
|
|
|
return $type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'image/x-icon';
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Get data URI (http://en.wikipedia.org/wiki/Data_URI_scheme).
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getDataUri()
|
|
|
|
{
|
2014-12-25 00:12:41 +01:00
|
|
|
if (empty($this->content)) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
return sprintf(
|
|
|
|
'data:%s;base64,%s',
|
2014-12-24 23:54:27 +01:00
|
|
|
$this->getType(),
|
2014-12-24 03:28:26 +01:00
|
|
|
base64_encode($this->content)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-10-19 20:42:31 +02:00
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Download and check if a resource exists.
|
2014-10-19 20:42:31 +02:00
|
|
|
*
|
2015-10-20 04:49:30 +02:00
|
|
|
* @param string $url URL
|
2017-01-15 22:05:50 +01:00
|
|
|
* @return \PicoFeed\Client\Client Client instance
|
2014-10-19 20:42:31 +02:00
|
|
|
*/
|
|
|
|
public function download($url)
|
|
|
|
{
|
|
|
|
$client = Client::getInstance();
|
|
|
|
$client->setConfig($this->config);
|
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
Logger::setMessage(get_called_class().' Download => '.$url);
|
|
|
|
|
|
|
|
try {
|
|
|
|
$client->execute($url);
|
2015-10-20 04:49:30 +02:00
|
|
|
} catch (ClientException $e) {
|
2014-12-24 03:28:26 +01:00
|
|
|
Logger::setMessage(get_called_class().' Download Failed => '.$e->getMessage());
|
2014-10-19 20:42:31 +02:00
|
|
|
}
|
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
return $client;
|
2014-10-19 20:42:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Check if a remote file exists.
|
|
|
|
*
|
|
|
|
* @param string $url URL
|
|
|
|
* @return bool
|
2014-10-19 20:42:31 +02:00
|
|
|
*/
|
|
|
|
public function exists($url)
|
|
|
|
{
|
2014-12-24 03:28:26 +01:00
|
|
|
return $this->download($url)->getContent() !== '';
|
2014-10-19 20:42:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Get the icon link for a website.
|
|
|
|
*
|
|
|
|
* @param string $website_link URL
|
|
|
|
* @param string $favicon_link optional URL
|
2014-10-19 20:42:31 +02:00
|
|
|
* @return string
|
|
|
|
*/
|
2015-01-18 15:20:36 +01:00
|
|
|
public function find($website_link, $favicon_link = '')
|
2014-10-19 20:42:31 +02:00
|
|
|
{
|
|
|
|
$website = new Url($website_link);
|
|
|
|
|
2015-01-18 15:20:36 +01:00
|
|
|
if ($favicon_link !== '') {
|
|
|
|
$icons = array($favicon_link);
|
|
|
|
} else {
|
|
|
|
$icons = $this->extract($this->download($website->getBaseUrl('/'))->getContent());
|
|
|
|
$icons[] = $website->getBaseUrl('/favicon.ico');
|
|
|
|
}
|
2014-10-19 20:42:31 +02:00
|
|
|
|
|
|
|
foreach ($icons as $icon_link) {
|
2015-01-28 02:13:16 +01:00
|
|
|
$icon_link = Url::resolve($icon_link, $website);
|
2014-12-24 03:28:26 +01:00
|
|
|
$resource = $this->download($icon_link);
|
|
|
|
$this->content = $resource->getContent();
|
|
|
|
$this->content_type = $resource->getContentType();
|
2014-10-19 20:42:31 +02:00
|
|
|
|
|
|
|
if ($this->content !== '') {
|
|
|
|
return $icon_link;
|
2015-01-18 15:20:36 +01:00
|
|
|
} elseif ($favicon_link !== '') {
|
|
|
|
return $this->find($website_link);
|
2014-10-19 20:42:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-10-20 04:49:30 +02:00
|
|
|
* Extract the icon links from the HTML.
|
|
|
|
*
|
|
|
|
* @param string $html HTML
|
2014-10-19 20:42:31 +02:00
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function extract($html)
|
|
|
|
{
|
|
|
|
$icons = array();
|
|
|
|
|
|
|
|
if (empty($html)) {
|
|
|
|
return $icons;
|
|
|
|
}
|
|
|
|
|
|
|
|
$dom = XmlParser::getHtmlDocument($html);
|
|
|
|
|
|
|
|
$xpath = new DOMXpath($dom);
|
2016-01-12 02:03:13 +01:00
|
|
|
$elements = $xpath->query('//link[@rel="icon" or @rel="shortcut icon" or @rel="icon shortcut"]');
|
2014-10-19 20:42:31 +02:00
|
|
|
|
2015-10-20 04:49:30 +02:00
|
|
|
for ($i = 0; $i < $elements->length; ++$i) {
|
2014-10-19 20:42:31 +02:00
|
|
|
$icons[] = $elements->item($i)->getAttribute('href');
|
|
|
|
}
|
|
|
|
|
|
|
|
return $icons;
|
|
|
|
}
|
|
|
|
}
|