[add] show favicon of site
[add] fetch and cache favicon
This commit is contained in:
parent
f945bb9b05
commit
268682859a
5 changed files with 410 additions and 39 deletions
40
inc/DataAccess.php
Normal file
40
inc/DataAccess.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Favicon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataAccess is a wrapper used to read/write data locally or remotly
|
||||||
|
* Aside from SOLID principles, this wrapper is also useful to mock remote resources in unit tests
|
||||||
|
* Note: remote access warning are silenced because we don't care if a website is unreachable
|
||||||
|
**/
|
||||||
|
class DataAccess {
|
||||||
|
public function retrieveUrl($url) {
|
||||||
|
$this->set_context();
|
||||||
|
return @file_get_contents($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function retrieveHeader($url) {
|
||||||
|
$this->set_context();
|
||||||
|
return @get_headers($url, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveCache($file, $data) {
|
||||||
|
file_put_contents($file, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readCache($file) {
|
||||||
|
return file_get_contents($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function set_context() {
|
||||||
|
stream_context_set_default(
|
||||||
|
array(
|
||||||
|
'http' => array(
|
||||||
|
'method' => 'GET',
|
||||||
|
'timeout' => 10,
|
||||||
|
'header' => "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:20.0; Favicon; +https://github.com/ArthurHoaro/favicon) Gecko/20100101 Firefox/32.0\r\n",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
293
inc/Favicon.php
Normal file
293
inc/Favicon.php
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Favicon;
|
||||||
|
|
||||||
|
class Favicon
|
||||||
|
{
|
||||||
|
protected $url = '';
|
||||||
|
protected $cacheDir;
|
||||||
|
protected $cacheTimeout;
|
||||||
|
protected $dataAccess;
|
||||||
|
|
||||||
|
public function __construct($args = array())
|
||||||
|
{
|
||||||
|
if (isset($args['url'])) {
|
||||||
|
$this->url = $args['url'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cacheDir = __DIR__ . '/../../resources/cache';
|
||||||
|
$this->dataAccess = new DataAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cache($args = array()) {
|
||||||
|
if (isset($args['dir'])) {
|
||||||
|
$this->cacheDir = $args['dir'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($args['timeout'])) {
|
||||||
|
$this->cacheTimeout = $args['timeout'];
|
||||||
|
} else {
|
||||||
|
$this->cacheTimeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function baseUrl($url, $path = false)
|
||||||
|
{
|
||||||
|
$return = '';
|
||||||
|
|
||||||
|
if (!$url = parse_url($url)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scheme
|
||||||
|
$scheme = isset($url['scheme']) ? strtolower($url['scheme']) : null;
|
||||||
|
if ($scheme != 'http' && $scheme != 'https') {
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
$return .= "{$scheme}://";
|
||||||
|
|
||||||
|
// Username and password
|
||||||
|
if (isset($url['user'])) {
|
||||||
|
$return .= $url['user'];
|
||||||
|
if (isset($url['pass'])) {
|
||||||
|
$return .= ":{$url['pass']}";
|
||||||
|
}
|
||||||
|
$return .= '@';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostname
|
||||||
|
if( !isset($url['host']) ) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$return .= $url['host'];
|
||||||
|
|
||||||
|
// Port
|
||||||
|
if (isset($url['port'])) {
|
||||||
|
$return .= ":{$url['port']}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path
|
||||||
|
if( $path && isset($url['path']) ) {
|
||||||
|
$return .= $url['path'];
|
||||||
|
}
|
||||||
|
$return .= '/';
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function info($url)
|
||||||
|
{
|
||||||
|
if(empty($url) || $url === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$max_loop = 5;
|
||||||
|
|
||||||
|
// Discover real status by following redirects.
|
||||||
|
$loop = TRUE;
|
||||||
|
while ($loop && $max_loop-- > 0) {
|
||||||
|
$headers = $this->dataAccess->retrieveHeader($url);
|
||||||
|
$exploded = explode(' ', $headers[0]);
|
||||||
|
|
||||||
|
if( !isset($exploded[1]) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
list(,$status) = $exploded;
|
||||||
|
|
||||||
|
switch ($status) {
|
||||||
|
case '301':
|
||||||
|
case '302':
|
||||||
|
$url = $headers['Location'];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$loop = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('status' => $status, 'url' => $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function endRedirect($url) {
|
||||||
|
$out = $this->info($url);
|
||||||
|
return !empty($out['url']) ? $out['url'] : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find remote (or cached) favicon
|
||||||
|
* @return favicon URL, false if nothing was found
|
||||||
|
**/
|
||||||
|
public function get($url = '')
|
||||||
|
{
|
||||||
|
// URLs passed to this method take precedence.
|
||||||
|
if (!empty($url)) {
|
||||||
|
$this->url = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the base URL without the path for clearer concatenations.
|
||||||
|
$original = rtrim($this->baseUrl($this->url, true), '/');
|
||||||
|
$url = rtrim($this->endRedirect($this->baseUrl($this->url, false)), '/');
|
||||||
|
|
||||||
|
if(($favicon = $this->checkCache($url)) || ($favicon = $this->getFavicon($url))) {
|
||||||
|
$base = true;
|
||||||
|
}
|
||||||
|
elseif(($favicon = $this->checkCache($original)) || ($favicon = $this->getFavicon($original, false))) {
|
||||||
|
$base = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Save cache if necessary
|
||||||
|
$cache = $this->cacheDir . '/' . md5($base ? $url : $original);
|
||||||
|
if ($this->cacheTimeout && !file_exists($cache) || (is_writable($cache) && time() - filemtime($cache) > $this->cacheTimeout)) {
|
||||||
|
$this->dataAccess->saveCache($cache, $favicon);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFavicon($url, $checkDefault = true) {
|
||||||
|
$favicon = false;
|
||||||
|
|
||||||
|
if(empty($url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try /favicon.ico first.
|
||||||
|
if( $checkDefault ) {
|
||||||
|
$info = $this->info("{$url}/favicon.ico");
|
||||||
|
if ($info['status'] == '200') {
|
||||||
|
$favicon = $info['url'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if it's specified in a link tag in domain url.
|
||||||
|
if (!$favicon) {
|
||||||
|
$favicon = $this->getInPage($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the favicon is an absolute URL.
|
||||||
|
if( $favicon && filter_var($favicon, FILTER_VALIDATE_URL) === false ) {
|
||||||
|
$favicon = $url . '/' . $favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sometimes people lie, so check the status.
|
||||||
|
// And sometimes, it's not even an image. Sneaky bastards!
|
||||||
|
// If cacheDir isn't writable, that's not our problem
|
||||||
|
if ($favicon && is_writable($this->cacheDir) && !$this->checkImageMType($favicon)) {
|
||||||
|
$favicon = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getInPage($url) {
|
||||||
|
$html = $this->dataAccess->retrieveUrl("{$url}/");
|
||||||
|
preg_match('!<head.*?>.*</head>!ims', $html, $match);
|
||||||
|
|
||||||
|
if(empty($match) || count($match) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$head = $match[0];
|
||||||
|
|
||||||
|
$dom = new \DOMDocument();
|
||||||
|
// Use error supression, because the HTML might be too malformed.
|
||||||
|
if (@$dom->loadHTML($head)) {
|
||||||
|
$links = $dom->getElementsByTagName('link');
|
||||||
|
foreach ($links as $link) {
|
||||||
|
if ($link->hasAttribute('rel') && strtolower($link->getAttribute('rel')) == 'shortcut icon') {
|
||||||
|
return $link->getAttribute('href');
|
||||||
|
} elseif ($link->hasAttribute('rel') && strtolower($link->getAttribute('rel')) == 'icon') {
|
||||||
|
return $link->getAttribute('href');
|
||||||
|
} elseif ($link->hasAttribute('href') && strpos($link->getAttribute('href'), 'favicon') !== FALSE) {
|
||||||
|
return $link->getAttribute('href');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkCache($url) {
|
||||||
|
if ($this->cacheTimeout) {
|
||||||
|
$cache = $this->cacheDir . '/' . md5($url);
|
||||||
|
if (file_exists($cache) && is_readable($cache) && (time() - filemtime($cache) < $this->cacheTimeout)) {
|
||||||
|
return $this->dataAccess->readCache($cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkImageMType($url) {
|
||||||
|
$tmpFile = $this->cacheDir . '/tmp.ico';
|
||||||
|
|
||||||
|
$fileContent = $this->dataAccess->retrieveUrl($url);
|
||||||
|
$this->dataAccess->saveCache($tmpFile, $fileContent);
|
||||||
|
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
|
$isImage = strpos(finfo_file($finfo, $tmpFile), 'image') !== false;
|
||||||
|
finfo_close($finfo);
|
||||||
|
|
||||||
|
unlink($tmpFile);
|
||||||
|
|
||||||
|
return $isImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getCacheDir()
|
||||||
|
{
|
||||||
|
return $this->cacheDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $cacheDir
|
||||||
|
*/
|
||||||
|
public function setCacheDir($cacheDir)
|
||||||
|
{
|
||||||
|
$this->cacheDir = $cacheDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getCacheTimeout()
|
||||||
|
{
|
||||||
|
return $this->cacheTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $cacheTimeout
|
||||||
|
*/
|
||||||
|
public function setCacheTimeout($cacheTimeout)
|
||||||
|
{
|
||||||
|
$this->cacheTimeout = $cacheTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUrl()
|
||||||
|
{
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $url
|
||||||
|
*/
|
||||||
|
public function setUrl($url)
|
||||||
|
{
|
||||||
|
$this->url = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DataAccess $dataAccess
|
||||||
|
*/
|
||||||
|
public function setDataAccess($dataAccess)
|
||||||
|
{
|
||||||
|
$this->dataAccess = $dataAccess;
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,9 +69,9 @@ h1 { font-size:20pt; font-weight:bold; font-style:italic; margin-bottom:20px; }
|
||||||
|
|
||||||
/* Small tab on the left of each link with edit/delete buttons. */
|
/* Small tab on the left of each link with edit/delete buttons. */
|
||||||
.button_edit, .button_delete { border-radius:0; box-shadow:none; border-style:none; border-width:0; padding:0; background:none; }
|
.button_edit, .button_delete { border-radius:0; box-shadow:none; border-style:none; border-width:0; padding:0; background:none; }
|
||||||
.linkeditbuttons {
|
.linkeditbuttons {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
left:-1px;
|
left:-1px;
|
||||||
padding:4px 2px 2px 2px;
|
padding:4px 2px 2px 2px;
|
||||||
background-color:#f0f0f0;
|
background-color:#f0f0f0;
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ cursor:pointer;
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
||||||
width:auto;
|
width:auto;
|
||||||
padding:0 10px 5px 10px;
|
padding:0 10px 5px 10px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pageheader a
|
#pageheader a
|
||||||
|
@ -282,7 +282,7 @@ font-size:9pt;
|
||||||
.thumbnail { float:left; margin-right: 10px; }
|
.thumbnail { float:left; margin-right: 10px; }
|
||||||
.linkcontainer { position: static; margin-left:130px; }
|
.linkcontainer { position: static; margin-left:130px; }
|
||||||
*/
|
*/
|
||||||
|
.favicon {width:16px;height:16px;margin-right:0.1em;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ font-size:9pt;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
background-color: rgba(0, 0, 0, 0.4); /* FF3+, Saf3+, Opera 10.10+, Chrome, IE9 */
|
background-color: rgba(0, 0, 0, 0.4); /* FF3+, Saf3+, Opera 10.10+, Chrome, IE9 */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000,endColorstr=#66000000); /* IE6IE9 */
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000,endColorstr=#66000000); /* IE6IE9 */
|
||||||
text-shadow:2px 2px 1px #000000;
|
text-shadow:2px 2px 1px #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Minimal customisation for jQuery widgets */
|
/* Minimal customisation for jQuery widgets */
|
||||||
|
@ -337,7 +337,7 @@ box-shadow:2px 2px 20px 2px #333333;
|
||||||
|
|
||||||
div.daily
|
div.daily
|
||||||
{
|
{
|
||||||
font-family: Georgia, 'DejaVu Serif', Norasi, serif;
|
font-family: Georgia, 'DejaVu Serif', Norasi, serif;
|
||||||
background-color: #E6D6BE;
|
background-color: #E6D6BE;
|
||||||
/* Background paper texture by BashCorpo:
|
/* Background paper texture by BashCorpo:
|
||||||
http://www.bashcorpo.dk/textures.php
|
http://www.bashcorpo.dk/textures.php
|
||||||
|
@ -356,7 +356,7 @@ div.daily
|
||||||
#daily_col3 { float:left;position:relative; width:33%;}
|
#daily_col3 { float:left;position:relative; width:33%;}
|
||||||
|
|
||||||
div.dailyAbout
|
div.dailyAbout
|
||||||
{
|
{
|
||||||
float:left;
|
float:left;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
font-size: 8pt;
|
font-size: 8pt;
|
||||||
|
@ -364,21 +364,21 @@ div.dailyAbout
|
||||||
left:10px;
|
left:10px;
|
||||||
top: 15px;
|
top: 15px;
|
||||||
padding: 5px 5px 5px 5px;
|
padding: 5px 5px 5px 5px;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
}
|
}
|
||||||
div.dailyAbout a { color: #890500; }
|
div.dailyAbout a { color: #890500; }
|
||||||
div.dailyTitle
|
div.dailyTitle
|
||||||
{
|
{
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 44pt;
|
font-size: 44pt;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
padding:10px 20px 0px 20px;
|
padding:10px 20px 0px 20px;
|
||||||
}
|
}
|
||||||
div.dailyDate
|
div.dailyDate
|
||||||
{
|
{
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
padding:0px 20px 30px 20px;
|
padding:0px 20px 30px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,19 +392,19 @@ div.dailyEntry
|
||||||
div.dailyEntry a { text-decoration:none; color: #890500; }
|
div.dailyEntry a { text-decoration:none; color: #890500; }
|
||||||
div.dailyEntryTags { font-size:7.75pt; }
|
div.dailyEntryTags { font-size:7.75pt; }
|
||||||
div.dailyEntryTitle { font-size:18pt; font-weight:bold;}
|
div.dailyEntryTitle { font-size:18pt; font-weight:bold;}
|
||||||
div.dailyEntryThumbnail
|
div.dailyEntryThumbnail
|
||||||
{
|
{
|
||||||
width:100%;
|
width:100%;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
background-color:rgb(128,128,128);
|
background-color:rgb(128,128,128);
|
||||||
background:url(../images/50pc_transparent.png);
|
background:url(../images/50pc_transparent.png);
|
||||||
padding:4px 0px 2px 0px;
|
padding:4px 0px 2px 0px;
|
||||||
}
|
}
|
||||||
div.dailyEntryDescription
|
div.dailyEntryDescription
|
||||||
{
|
{
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
text-align:justify;
|
text-align:justify;
|
||||||
overflow:auto;
|
overflow:auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ div.dailyEntryDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For lazy images loading in picture wall.
|
/* For lazy images loading in picture wall.
|
||||||
using http://www.appelsiini.net/projects/lazyload
|
using http://www.appelsiini.net/projects/lazyload
|
||||||
*/
|
*/
|
||||||
.lazyimage { display:none; }
|
.lazyimage { display:none; }
|
||||||
|
|
||||||
|
@ -463,7 +463,7 @@ div.dailyDate { font-size: 11pt;padding:0px; display:block; }
|
||||||
div.dailyEntryTitle { font-size:16pt; font-weight:bold;}
|
div.dailyEntryTitle { font-size:16pt; font-weight:bold;}
|
||||||
div.dailyEntryDescription { font-size:10pt; }
|
div.dailyEntryDescription { font-size:10pt; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Highlight search results */
|
/* Highlight search results */
|
||||||
.highlight { background-color: #FFFF33; }
|
.highlight { background-color: #FFFF33; }
|
||||||
|
|
50
index.php
50
index.php
|
@ -22,9 +22,11 @@
|
||||||
$GLOBALS['config']['OPEN_SHAARLI'] = false; // If true, anyone can add/edit/delete links without having to login
|
$GLOBALS['config']['OPEN_SHAARLI'] = false; // If true, anyone can add/edit/delete links without having to login
|
||||||
$GLOBALS['config']['HIDE_TIMESTAMPS'] = false; // If true, the moment when links were saved are not shown to users that are not logged in.
|
$GLOBALS['config']['HIDE_TIMESTAMPS'] = false; // If true, the moment when links were saved are not shown to users that are not logged in.
|
||||||
$GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links.
|
$GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links.
|
||||||
|
$GLOBALS['config']['ENABLE_FAVICON'] = true; // Enable favicon in links.
|
||||||
$GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr)
|
$GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr)
|
||||||
$GLOBALS['config']['PAGECACHE'] = 'pagecache'; // Page cache directory.
|
$GLOBALS['config']['PAGECACHE'] = 'pagecache'; // Page cache directory.
|
||||||
$GLOBALS['config']['ENABLE_LOCALCACHE'] = true; // Enable Shaarli to store thumbnail in a local cache. Disable to reduce webspace usage.
|
$GLOBALS['config']['ENABLE_LOCALCACHE'] = true; // Enable Shaarli to store thumbnail in a local cache. Disable to reduce webspace usage.
|
||||||
|
// Care if favicon is active and local cache are false serve page can be long
|
||||||
$GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable.
|
$GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable.
|
||||||
$GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli.
|
$GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli.
|
||||||
$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours
|
$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours
|
||||||
|
@ -344,7 +346,7 @@ function isLoggedIn()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force logout.
|
// Force logout.
|
||||||
function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SESSION['ip']); unset($_SESSION['username']); unset($_SESSION['privateonly']); }
|
function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SESSION['ip']); unset($_SESSION['username']); unset($_SESSION['privateonly']); }
|
||||||
setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH);
|
setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,7 +915,7 @@ function showRSS()
|
||||||
else $linksToDisplay = $LINKSDB;
|
else $linksToDisplay = $LINKSDB;
|
||||||
$nblinksToDisplay = 50; // Number of links to display.
|
$nblinksToDisplay = 50; // Number of links to display.
|
||||||
if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
|
if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
|
||||||
{
|
{
|
||||||
$nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
|
$nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,7 +990,7 @@ function showATOM()
|
||||||
else $linksToDisplay = $LINKSDB;
|
else $linksToDisplay = $LINKSDB;
|
||||||
$nblinksToDisplay = 50; // Number of links to display.
|
$nblinksToDisplay = 50; // Number of links to display.
|
||||||
if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
|
if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
|
||||||
{
|
{
|
||||||
$nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
|
$nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1563,7 +1565,7 @@ function renderPage()
|
||||||
$title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet).
|
$title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet).
|
||||||
$description = (empty($_GET['description']) ? '' : $_GET['description']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that]
|
$description = (empty($_GET['description']) ? '' : $_GET['description']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that]
|
||||||
$tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL
|
$tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL
|
||||||
$private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL
|
$private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL
|
||||||
if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url;
|
if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url;
|
||||||
// If this is an HTTP link, we try go get the page to extact the title (otherwise we will to straight to the edit form.)
|
// If this is an HTTP link, we try go get the page to extact the title (otherwise we will to straight to the edit form.)
|
||||||
if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http')
|
if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http')
|
||||||
|
@ -1574,7 +1576,7 @@ function renderPage()
|
||||||
{
|
{
|
||||||
// Look for charset in html header.
|
// Look for charset in html header.
|
||||||
preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
|
preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
|
||||||
|
|
||||||
// If found, extract encoding.
|
// If found, extract encoding.
|
||||||
if (!empty($meta[0]))
|
if (!empty($meta[0]))
|
||||||
{
|
{
|
||||||
|
@ -1584,7 +1586,7 @@ function renderPage()
|
||||||
$html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8';
|
$html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8';
|
||||||
}
|
}
|
||||||
else { $html_charset = 'utf-8'; }
|
else { $html_charset = 'utf-8'; }
|
||||||
|
|
||||||
// Extract title
|
// Extract title
|
||||||
$title = html_extract_title($data);
|
$title = html_extract_title($data);
|
||||||
if (!empty($title))
|
if (!empty($title))
|
||||||
|
@ -2052,6 +2054,42 @@ function lazyThumbnail($url,$href=false)
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function returnFavicon($url){
|
||||||
|
if(!$GLOBALS['config']['ENABLE_FAVICON']){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$faviconHash = md5($url);
|
||||||
|
$path = substr($faviconHash, 0,2).'/'.substr($faviconHash, 2,2);
|
||||||
|
$faviconPath = $GLOBALS['config']['CACHEDIR'].'/'.$path.'/'.$faviconHash.'.ico';
|
||||||
|
if($GLOBALS['config']['ENABLE_LOCALCACHE'] === true && file_exists($faviconPath)){
|
||||||
|
$content = file_get_contents($faviconPath);
|
||||||
|
return '<img class="favicon" alt="favicon" src="data:image/ico;base64,'.base64_encode($content).'"/>';
|
||||||
|
}
|
||||||
|
if(file_exists($GLOBALS['config']['CACHEDIR'].'/'.$path.'/'.$faviconHash)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
require_once 'inc/DataAccess.php';
|
||||||
|
require_once 'inc/Favicon.php';
|
||||||
|
$favicon = new \Favicon\Favicon();
|
||||||
|
$urlOfFavicon = $favicon->get($url);
|
||||||
|
if(!$urlOfFavicon){
|
||||||
|
if($GLOBALS['config']['ENABLE_LOCALCACHE'] === true){
|
||||||
|
mkdir($GLOBALS['config']['CACHEDIR'].'/'.$path,0777,true);
|
||||||
|
touch($GLOBALS['config']['CACHEDIR'].'/'.$path.'/'.$faviconHash);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($GLOBALS['config']['ENABLE_LOCALCACHE'] === true && !is_dir($GLOBALS['config']['CACHEDIR'].'/'.$path.'/')){
|
||||||
|
mkdir($GLOBALS['config']['CACHEDIR'].'/'.$path,0777,true);
|
||||||
|
}
|
||||||
|
$content = file_get_contents($urlOfFavicon);
|
||||||
|
if($GLOBALS['config']['ENABLE_LOCALCACHE'] === true){
|
||||||
|
file_put_contents($faviconPath, $content);
|
||||||
|
}
|
||||||
|
return '<img class="favicon" alt="favicon" src="data:image/ico;base64,'.base64_encode($content).'"/>';
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
// Installation
|
// Installation
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<input type="hidden" name="token" value="{$token}"><input type="hidden" name="delete_link"><input type="image" alt="Delete" src="images/delete_icon.png#" title="Delete" class="button_delete" onClick="return confirmDeleteLink();"></form>
|
<input type="hidden" name="token" value="{$token}"><input type="hidden" name="delete_link"><input type="image" alt="Delete" src="images/delete_icon.png#" title="Delete" class="button_delete" onClick="return confirmDeleteLink();"></form>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="linktitle"><a href="{$redirector}{$value.url|htmlspecialchars}">{$value.title|htmlspecialchars}</a></span>
|
<span class="linktitle">{function="returnFavicon($value.url)"}<a href="{$redirector}{$value.url|htmlspecialchars}">{$value.title|htmlspecialchars}</a></span>
|
||||||
<br>
|
<br>
|
||||||
{if="$value.description"}<div class="linkdescription"{if condition="$search_type=='permalink'"} style="max-height:none !important;"{/if}>{$value.description}</div>{/if}
|
{if="$value.description"}<div class="linkdescription"{if condition="$search_type=='permalink'"} style="max-height:none !important;"{/if}>{$value.description}</div>{/if}
|
||||||
{if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
|
{if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
|
||||||
|
@ -48,8 +48,8 @@
|
||||||
{else}
|
{else}
|
||||||
<span class="linkdate" title="Short link here"><a href="?{$value.linkdate|smallHash}">permalink</a> - </span>
|
<span class="linkdate" title="Short link here"><a href="?{$value.linkdate|smallHash}">permalink</a> - </span>
|
||||||
{/if}
|
{/if}
|
||||||
<div style="position:relative;display:inline;"><a href="http://qrfree.kaywa.com/?l=1&s=8&d={$scripturl|urlencode}%3F{$value.linkdate|smallHash}"
|
<div style="position:relative;display:inline;"><a href="http://qrfree.kaywa.com/?l=1&s=8&d={$scripturl|urlencode}%3F{$value.linkdate|smallHash}"
|
||||||
onclick="showQrCode(this); return false;" class="qrcode" data-permalink="{$scripturl}?{$value.linkdate|smallHash}"><img src="images/qrcode.png#" width="13" height="13" title="QR-Code"></a></div> -
|
onclick="showQrCode(this); return false;" class="qrcode" data-permalink="{$scripturl}?{$value.linkdate|smallHash}"><img src="images/qrcode.png#" width="13" height="13" title="QR-Code"></a></div> -
|
||||||
<span class="linkurl" title="Short link">{$value.url|htmlspecialchars}</span><br>
|
<span class="linkurl" title="Short link">{$value.url|htmlspecialchars}</span><br>
|
||||||
{if="$value.tags"}
|
{if="$value.tags"}
|
||||||
<div class="linktaglist">
|
<div class="linktaglist">
|
||||||
|
@ -65,12 +65,12 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{include="page.footer"}
|
{include="page.footer"}
|
||||||
|
|
||||||
<script language="JavaScript">
|
<script language="JavaScript">
|
||||||
// Remove any displayed QR-Code
|
// Remove any displayed QR-Code
|
||||||
function remove_qrcode()
|
function remove_qrcode()
|
||||||
{
|
{
|
||||||
var elem = document.getElementById("permalinkQrcode");
|
var elem = document.getElementById("permalinkQrcode");
|
||||||
if (elem) elem.parentNode.removeChild(elem);
|
if (elem) elem.parentNode.removeChild(elem);
|
||||||
return false;
|
return false;
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
|
|
||||||
// Show the QR-Code of a permalink (when the QR-Code icon is clicked).
|
// Show the QR-Code of a permalink (when the QR-Code icon is clicked).
|
||||||
function showQrCode(caller,loading=false)
|
function showQrCode(caller,loading=false)
|
||||||
{
|
{
|
||||||
// Dynamic javascript lib loading: We only load qr.js if the QR code icon is clicked:
|
// Dynamic javascript lib loading: We only load qr.js if the QR code icon is clicked:
|
||||||
if (typeof(qr)=='undefined') // Load qr.js only if not present.
|
if (typeof(qr)=='undefined') // Load qr.js only if not present.
|
||||||
{
|
{
|
||||||
|
@ -94,18 +94,18 @@
|
||||||
|
|
||||||
// Remove previous qrcode if present.
|
// Remove previous qrcode if present.
|
||||||
remove_qrcode();
|
remove_qrcode();
|
||||||
|
|
||||||
// Build the div which contains the QR-Code:
|
// Build the div which contains the QR-Code:
|
||||||
var element = document.createElement('div');
|
var element = document.createElement('div');
|
||||||
element.id="permalinkQrcode";
|
element.id="permalinkQrcode";
|
||||||
// Make QR-Code div commit sepuku when clicked:
|
// Make QR-Code div commit sepuku when clicked:
|
||||||
if ( element.attachEvent ){ element.attachEvent('onclick', 'this.parentNode.removeChild(this);' ); } // Damn IE
|
if ( element.attachEvent ){ element.attachEvent('onclick', 'this.parentNode.removeChild(this);' ); } // Damn IE
|
||||||
else { element.setAttribute('onclick', 'this.parentNode.removeChild(this);' ); }
|
else { element.setAttribute('onclick', 'this.parentNode.removeChild(this);' ); }
|
||||||
|
|
||||||
// Build the QR-Code:
|
// Build the QR-Code:
|
||||||
var image = qr.image({size: 8,value: caller.dataset.permalink});
|
var image = qr.image({size: 8,value: caller.dataset.permalink});
|
||||||
if (image)
|
if (image)
|
||||||
{
|
{
|
||||||
element.appendChild(image);
|
element.appendChild(image);
|
||||||
element.innerHTML+= "<br>Click to close";
|
element.innerHTML+= "<br>Click to close";
|
||||||
caller.parentNode.appendChild(element);
|
caller.parentNode.appendChild(element);
|
||||||
|
|
Loading…
Reference in a new issue