From 042095ae7a3cb4609f608449ad913dffb8175008 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Wed, 8 Jun 2016 09:31:51 +0200 Subject: [PATCH 01/14] [upd] change url to new repo --- README.md | 2 +- index.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bc74eda..1a54e9e 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ myShaarli Features : * Change date/time format More information on the project page: -https://forge.leslibres.org/projects/shaarli +https://forge.leslibres.org/Knah-Tsaeb/MyShaarli Requires php 5.1 diff --git a/index.php b/index.php index 0c3d247..563c49a 100644 --- a/index.php +++ b/index.php @@ -33,7 +33,7 @@ $GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty $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_URL'] = 'http://book.knah-tsaeb.org/shaarli_version.txt'; // Define last version of myShaarli -$GLOBALS['config']['UPDATECHECK_DOWNLOAD'] = 'https://forge.leslibres.org/projects/shaarli/repository'; +$GLOBALS['config']['UPDATECHECK_DOWNLOAD'] = 'https://forge.leslibres.org/Knah-Tsaeb/MyShaarli'; $GLOBALS['config']['ENABLE_UPDATECHECK'] = TRUE; $GLOBALS['config']['externalThumbshot'] = ''; // Url for external thumbnailer // exemple : http://images.thumbshots.com/image.aspx?cid=dgdfgdfg&v=1&w=120&url= @@ -172,14 +172,14 @@ function checkUpdate() file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date } // Compare versions: - $newestversion=file_get_contents($GLOBALS['config']['UPDATECHECK_FILENAME']); - if (version_compare(myShaarli_version,$newestversion)==0){ + $newestversion=trim(file_get_contents($GLOBALS['config']['UPDATECHECK_FILENAME'])); + if (version_compare( strtolower(myShaarli_version), strtolower($newestversion))==0){ return false; } - if (version_compare(myShaarli_version,$newestversion)==1){ + if (version_compare( strtolower(myShaarli_version), strtolower($newestversion))==1){ return 'You have future version ?!'; } - if (version_compare(myShaarli_version,$newestversion)==-1){ + if (version_compare( strtolower(myShaarli_version), strtolower($newestversion))==-1){ return 'New update of myShaarli available.'; } return false; From f981ab8a17e873842499bdd9d6b55932a321da91 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Wed, 8 Jun 2016 11:01:13 +0200 Subject: [PATCH 02/14] [add] implemented opensearch plugins --- README.md | 1 + index.php | 10 ++++++++++ tpl/myShaarli/includes.html | 5 +++-- tpl/myShaarli/opensearch.html | 15 +++++++++++++++ tpl/myShaarli_Columns/includes.html | 5 +++-- tpl/myShaarli_Columns/opensearch.html | 15 +++++++++++++++ tpl/original/includes.html | 5 +++-- tpl/original/opensearch.html | 15 +++++++++++++++ 8 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 tpl/myShaarli/opensearch.html create mode 100644 tpl/myShaarli_Columns/opensearch.html create mode 100644 tpl/original/opensearch.html diff --git a/README.md b/README.md index 1a54e9e..4550b9a 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ myShaarli Features : * Add link to archive.org (qwertygc https://github.com/nodiscc/Shaarli/commit/b113dc8e6bba052883297ab575dd36fd3073805e) * myShaali can use Firefox social API (Marsup https://github.com/shaarli/Shaarli/commit/d33c5d4c3b9c70441391a08e8bcb2a8c639a4635) * myShaali can post original article to wallabag (nodiscc https://github.com/nodiscc/Shaarli/tree/new-plugin-system/tpl/plugins/wallabag) + * myShaali implement OpenSearch (ArthurHoaro https://github.com/shaarli/Shaarli/issues/176) * Few small fix * You can upgrade original Shaarli to myShaarli without lost your data * You can define url origin of update diff --git a/index.php b/index.php index 563c49a..890c9f9 100644 --- a/index.php +++ b/index.php @@ -1350,6 +1350,16 @@ function renderPage() exit; } + // Display openseach plugin (XML) + if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=opensearch')) { + header('Content-Type: application/xml; charset=utf-8'); + $PAGE = new pageBuilder; + $PAGE->assign('serverurl', $GLOBALS['title']); + $PAGE->assign('pagetitle',$GLOBALS['title']); + $PAGE->renderPage('opensearch'); + exit; + } + // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) if (isset($_GET['addtag'])) { diff --git a/tpl/myShaarli/includes.html b/tpl/myShaarli/includes.html index df05815..f538185 100644 --- a/tpl/myShaarli/includes.html +++ b/tpl/myShaarli/includes.html @@ -5,8 +5,9 @@ - + - \ No newline at end of file + + diff --git a/tpl/myShaarli/opensearch.html b/tpl/myShaarli/opensearch.html new file mode 100644 index 0000000..2eb9851 --- /dev/null +++ b/tpl/myShaarli/opensearch.html @@ -0,0 +1,15 @@ + + + myShaarli search - {$pagetitle} + myShaarli search - {$pagetitle} + + + + UTF-8 + Knah Tsaeb myShaarly - https://github.com/Knah-Tsaeb/myShaarli + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlz AAALEwAACxMBAJqcGAAAAAd0SU1FB98HEA4tDZmAhI0AAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0 ZWQgd2l0aCBHSU1QZC5lBwAAAhJJREFUOMuVUz1oU1EYPcm90iTNnxCTtImtD6VdoghShzq0xPLy + DEpEcdAuoUgVC4JDHERx6ioU0UVQC3VyU4dAMKb+pNI6qBTaQqnSxpBgan6qTZq89z6HWIkhofEs l3s45/B99/suQxPcuOdnWeOXEedBPnjsRNfcQjxH+B8cuqC7c3OG0+05ToeH+d1mOlZPDF62tZv3 KwMOQb7e0c2t7QaOHylFMLh2RdLzSqper6m9HBk2C66e0kL/kK7NuZfh8+wW7J0cboFj6VMZ0Wel 6Lv78vGmFVh6lNMXr1rPfk8QZqIlzL4uIrEiY3VJRt9RI8xWJih606O1j5v5bY+2NsBmND1/+vBn + 4cA+Pc6f2wOPx4BOZxsujXZgIwPEX21Oxx9nVms9/wS8ncyu5xaFqXJei5eRAkJj3RgbcSPyYgOn BhxYz6hf69+A1xMqK71ZXt66EjzjxuSTFIp5DySfgm9rMlTSZHacQmIxO6/+6r3W5RrV6fP92K32 Qi73YXz8fcLuEE6ufEjuvA+iKBIRkd/vp2AwSEREXq+3oVHbkNRW6UKhoBaLRQCA3W6HJEmmlgL+ LolGo2Ws2uWfk7UUUKlUqmO12WCxWAAARI1b541IWZYT6XTaHQgEwDkHESGZTCIWi+Va+kiSJN0K + hUK0jYmJCRJFcaphm81CfD7fg0qlEmSMcQDTjLGhcDgs1+t+Ay6pzgTLZnNuAAAAAElFTkSuQmCC + + diff --git a/tpl/myShaarli_Columns/includes.html b/tpl/myShaarli_Columns/includes.html index 6686e9b..4186b98 100644 --- a/tpl/myShaarli_Columns/includes.html +++ b/tpl/myShaarli_Columns/includes.html @@ -5,8 +5,9 @@ - + - \ No newline at end of file + + diff --git a/tpl/myShaarli_Columns/opensearch.html b/tpl/myShaarli_Columns/opensearch.html new file mode 100644 index 0000000..2eb9851 --- /dev/null +++ b/tpl/myShaarli_Columns/opensearch.html @@ -0,0 +1,15 @@ + + + myShaarli search - {$pagetitle} + myShaarli search - {$pagetitle} + + + + UTF-8 + Knah Tsaeb myShaarly - https://github.com/Knah-Tsaeb/myShaarli + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlz AAALEwAACxMBAJqcGAAAAAd0SU1FB98HEA4tDZmAhI0AAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0 ZWQgd2l0aCBHSU1QZC5lBwAAAhJJREFUOMuVUz1oU1EYPcm90iTNnxCTtImtD6VdoghShzq0xPLy + DEpEcdAuoUgVC4JDHERx6ioU0UVQC3VyU4dAMKb+pNI6qBTaQqnSxpBgan6qTZq89z6HWIkhofEs l3s45/B99/suQxPcuOdnWeOXEedBPnjsRNfcQjxH+B8cuqC7c3OG0+05ToeH+d1mOlZPDF62tZv3 KwMOQb7e0c2t7QaOHylFMLh2RdLzSqper6m9HBk2C66e0kL/kK7NuZfh8+wW7J0cboFj6VMZ0Wel 6Lv78vGmFVh6lNMXr1rPfk8QZqIlzL4uIrEiY3VJRt9RI8xWJih606O1j5v5bY+2NsBmND1/+vBn + 4cA+Pc6f2wOPx4BOZxsujXZgIwPEX21Oxx9nVms9/wS8ncyu5xaFqXJei5eRAkJj3RgbcSPyYgOn BhxYz6hf69+A1xMqK71ZXt66EjzjxuSTFIp5DySfgm9rMlTSZHacQmIxO6/+6r3W5RrV6fP92K32 Qi73YXz8fcLuEE6ufEjuvA+iKBIRkd/vp2AwSEREXq+3oVHbkNRW6UKhoBaLRQCA3W6HJEmmlgL+ LolGo2Ws2uWfk7UUUKlUqmO12WCxWAAARI1b541IWZYT6XTaHQgEwDkHESGZTCIWi+Va+kiSJN0K + hUK0jYmJCRJFcaphm81CfD7fg0qlEmSMcQDTjLGhcDgs1+t+Ay6pzgTLZnNuAAAAAElFTkSuQmCC + + diff --git a/tpl/original/includes.html b/tpl/original/includes.html index c0fe905..2fec02c 100644 --- a/tpl/original/includes.html +++ b/tpl/original/includes.html @@ -5,8 +5,9 @@ - + - \ No newline at end of file + + diff --git a/tpl/original/opensearch.html b/tpl/original/opensearch.html new file mode 100644 index 0000000..2eb9851 --- /dev/null +++ b/tpl/original/opensearch.html @@ -0,0 +1,15 @@ + + + myShaarli search - {$pagetitle} + myShaarli search - {$pagetitle} + + + + UTF-8 + Knah Tsaeb myShaarly - https://github.com/Knah-Tsaeb/myShaarli + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlz AAALEwAACxMBAJqcGAAAAAd0SU1FB98HEA4tDZmAhI0AAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0 ZWQgd2l0aCBHSU1QZC5lBwAAAhJJREFUOMuVUz1oU1EYPcm90iTNnxCTtImtD6VdoghShzq0xPLy + DEpEcdAuoUgVC4JDHERx6ioU0UVQC3VyU4dAMKb+pNI6qBTaQqnSxpBgan6qTZq89z6HWIkhofEs l3s45/B99/suQxPcuOdnWeOXEedBPnjsRNfcQjxH+B8cuqC7c3OG0+05ToeH+d1mOlZPDF62tZv3 KwMOQb7e0c2t7QaOHylFMLh2RdLzSqper6m9HBk2C66e0kL/kK7NuZfh8+wW7J0cboFj6VMZ0Wel 6Lv78vGmFVh6lNMXr1rPfk8QZqIlzL4uIrEiY3VJRt9RI8xWJih606O1j5v5bY+2NsBmND1/+vBn + 4cA+Pc6f2wOPx4BOZxsujXZgIwPEX21Oxx9nVms9/wS8ncyu5xaFqXJei5eRAkJj3RgbcSPyYgOn BhxYz6hf69+A1xMqK71ZXt66EjzjxuSTFIp5DySfgm9rMlTSZHacQmIxO6/+6r3W5RrV6fP92K32 Qi73YXz8fcLuEE6ufEjuvA+iKBIRkd/vp2AwSEREXq+3oVHbkNRW6UKhoBaLRQCA3W6HJEmmlgL+ LolGo2Ws2uWfk7UUUKlUqmO12WCxWAAARI1b541IWZYT6XTaHQgEwDkHESGZTCIWi+Va+kiSJN0K + hUK0jYmJCRJFcaphm81CfD7fg0qlEmSMcQDTjLGhcDgs1+t+Ay6pzgTLZnNuAAAAAElFTkSuQmCC + + From a1c3e68e7aba753de43c59f94019661612b87690 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 22 Nov 2015 15:47:41 +0100 Subject: [PATCH 03/14] Fixes #382: Bookmarklet can not retrieve title when there is a quotation mark in it bookmarklet fields weren't correctly escaped --- index.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/index.php b/index.php index 890c9f9..f01caa0 100644 --- a/index.php +++ b/index.php @@ -1682,11 +1682,13 @@ function renderPage() { $link_is_new = true; // This is a new link $linkdate = strval(date('Ymd_His')); - $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] - $tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL - $via = (empty($_GET['via']) ? '' : $_GET['via'] ); - $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL + // Get title if it was provided in URL (by the bookmarklet). + $title = empty($_GET['title']) ? '' : htmlspecialchars($_GET['title']); + // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] + $description = (empty($_GET['description']) ? '' : htmlspecialchars($_GET['description'])); + $tags = (empty($_GET['tags']) ? '' : htmlspecialchars($_GET['tags'] )); + $via = (empty($_GET['via']) ? '' : htmlspecialchars($_GET['via'] )); + $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); 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 (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http') From 167066f4bb879f7e8f7f6dfe06be9eb460d38631 Mon Sep 17 00:00:00 2001 From: Nicolas Danelon Date: Tue, 24 Nov 2015 12:29:26 -0300 Subject: [PATCH 04/14] cleanup: remove json_encode() (built-in since PHP 5.2) See http://php.net/manual/en/function.json-encode.php Legacy since php 5.2.x . If php5.3 is required for the install script --- index.php | 187 +----------------------------------------------------- 1 file changed, 1 insertion(+), 186 deletions(-) diff --git a/index.php b/index.php index f01caa0..ee8a507 100644 --- a/index.php +++ b/index.php @@ -2299,192 +2299,7 @@ function install() exit; } -// Generates the timezone selection form and javascript. -// Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected. -// Output: array(html,js) -// Example: list($htmlform,$js) = templateTZform('Europe/Paris'); // Europe/Paris pre-selected. -// Returns array('','') if server does not support timezones list. (eg. php 5.1 on free.fr) -function templateTZform($ptz=false) -{ - if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr - { - // Try to split the provided timezone. - if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; } - $spos=strpos($ptz,'/'); $pcontinent=substr($ptz,0,$spos); $pcity=substr($ptz,$spos+1); - - // Display config form: - $timezone_form = ''; - $timezone_js = ''; - // The list is in the forme "Europe/Paris", "America/Argentina/Buenos_Aires"... - // We split the list in continents/cities. - $continents = array(); - $cities = array(); - foreach(timezone_identifiers_list() as $tz) - { - if ($tz=='UTC') $tz='UTC/UTC'; - $spos = strpos($tz,'/'); - if ($spos!==false) - { - $continent=substr($tz,0,$spos); $city=substr($tz,$spos+1); - $continents[$continent]=1; - if (!isset($cities[$continent])) $cities[$continent]=''; - $cities[$continent].=''; - } - } - $continents_html = ''; - $continents = array_keys($continents); - foreach($continents as $continent) - $continents_html.=''; - $cities_html = $cities[$pcontinent]; - $timezone_form = "Continent: "; - $timezone_form .= "    City:
"; - $timezone_js = "" ; - return array($timezone_form,$timezone_js); - } - return array('',''); -} - -// Tells if a timezone is valid or not. -// If not valid, returns false. -// If system does not support timezone list, returns false. -function isTZvalid($continent,$city) -{ - $tz = $continent.'/'.$city; - if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr - { - if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone ? - return true; - } - return false; -} -if (!function_exists('json_encode')) { - function json_encode($data) { - switch ($type = gettype($data)) { - case 'NULL': - return 'null'; - case 'boolean': - return ($data ? 'true' : 'false'); - case 'integer': - case 'double': - case 'float': - return $data; - case 'string': - return '"' . addslashes($data) . '"'; - case 'object': - $data = get_object_vars($data); - case 'array': - $output_index_count = 0; - $output_indexed = array(); - $output_associative = array(); - foreach ($data as $key => $value) { - $output_indexed[] = json_encode($value); - $output_associative[] = json_encode($key) . ':' . json_encode($value); - if ($output_index_count !== NULL && $output_index_count++ !== $key) { - $output_index_count = NULL; - } - } - if ($output_index_count !== NULL) { - return '[' . implode(',', $output_indexed) . ']'; - } else { - return '{' . implode(',', $output_associative) . '}'; - } - default: - return ''; // Not supported - } - } -} - -// Webservices (for use with jQuery/jQueryUI) -// eg. index.php?ws=tags&term=minecr -function processWS() -{ - if (empty($_GET['ws']) || empty($_GET['term'])) return; - $term = $_GET['term']; - $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). - header('Content-Type: application/json; charset=utf-8'); - - // Search in tags (case insentitive, cumulative search) - if ($_GET['ws']=='tags') - { - $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") - $addtags=''; if ($tags) $addtags=implode(' ',$tags).' '; // We will pre-pend previous tags - $suggested=array(); - /* To speed up things, we store list of tags in session */ - if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); - foreach($_SESSION['tags'] as $key=>$value) - { - if (startsWith($key,$last,$case=false) && !in_array($key,$tags)) $suggested[$addtags.$key.' ']=0; - } - echo json_encode(array_keys($suggested)); - exit; - } - - // Search a single tag (case sentitive, single tag search) - if ($_GET['ws']=='singletag') - { - /* To speed up things, we store list of tags in session */ - if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); - foreach($_SESSION['tags'] as $key=>$value) - { - if (startsWith($key,$term,$case=true)) $suggested[$key]=0; - } - echo json_encode(array_keys($suggested)); - exit; - } -} - -function getAllTheme(){ - $allTheme = glob('tpl/*', GLOB_ONLYDIR); - foreach ($allTheme as $value) { - $themes[] = str_replace('tpl/', '', $value); - } - return $themes; -} - -// Re-write configuration file according to globals. -// Requires some $GLOBALS to be set (login,hash,salt,title). -// If the config file cannot be saved, an error message is dislayed and the user is redirected to "Tools" menu. -// (otherwise, the function simply returns.) -function writeConfig() -{ - if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. - $config = "alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';'; - exit; - } -} - -/* Because some f*cking services like Flickr require an extra HTTP request to get the thumbnail URL, +/* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. The following function takes the URL a link (eg. a flickr page) and return the proper thumbnail. This function is called by passing the url: From 20d859380adbe3d17699230e48ba9b4bdf8ab8cb Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 5 Dec 2015 11:05:08 +0100 Subject: [PATCH 05/14] Fixes #399 - show single link title as page title --- index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/index.php b/index.php index ee8a507..a2a1bbf 100644 --- a/index.php +++ b/index.php @@ -2004,6 +2004,7 @@ function buildLinkList($PAGE,$LINKSDB) $PAGE->assign('next_page_url',$next_page_url); $PAGE->assign('page_current',$page); $PAGE->assign('page_max',$pagecount); + $PAGE->assign('pagetitle', $GLOBALS['pagetitle']); $PAGE->assign('result_count',count($linksToDisplay)); $PAGE->assign('search_type',$search_type); $PAGE->assign('search_crits',$search_crits); From ad03ee9f5f20f2f139292228809b80a537ab1eb6 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Wed, 8 Jun 2016 11:59:42 +0200 Subject: [PATCH 06/14] Bump version --- index.php | 2 +- shaarli_version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.php b/index.php index a2a1bbf..d629a58 100644 --- a/index.php +++ b/index.php @@ -54,7 +54,7 @@ if (is_file($GLOBALS['config']['DATADIR'].'/options.php')){ require($GLOBALS['config']['DATADIR'].'/options.php'); } -define('myShaarli_version','1.1.2'); +define('myShaarli_version','1.1.3'); define('PHPPREFIX',''); // Suffix to encapsulate data in php code. // http://server.com/x/shaarli --> /shaarli/ diff --git a/shaarli_version.txt b/shaarli_version.txt index 45a1b3f..781dcb0 100644 --- a/shaarli_version.txt +++ b/shaarli_version.txt @@ -1 +1 @@ -1.1.2 +1.1.3 From b7b0894720bff6dd98af83ca0aa4dbf907876467 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Wed, 8 Jun 2016 12:11:55 +0200 Subject: [PATCH 07/14] [fix] bad merge 167066f4bb --- index.php | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/index.php b/index.php index d629a58..329b464 100644 --- a/index.php +++ b/index.php @@ -2300,6 +2300,149 @@ function install() exit; } +// Generates the timezone selection form and javascript. +// Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected. +// Output: array(html,js) +// Example: list($htmlform,$js) = templateTZform('Europe/Paris'); // Europe/Paris pre-selected. +// Returns array('','') if server does not support timezones list. (eg. php 5.1 on free.fr) +function templateTZform($ptz=false) +{ + if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr + { + // Try to split the provided timezone. + if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; } + $spos=strpos($ptz,'/'); $pcontinent=substr($ptz,0,$spos); $pcity=substr($ptz,$spos+1); + // Display config form: + $timezone_form = ''; + $timezone_js = ''; + // The list is in the forme "Europe/Paris", "America/Argentina/Buenos_Aires"... + // We split the list in continents/cities. + $continents = array(); + $cities = array(); + foreach(timezone_identifiers_list() as $tz) + { + if ($tz=='UTC') $tz='UTC/UTC'; + $spos = strpos($tz,'/'); + if ($spos!==false) + { + $continent=substr($tz,0,$spos); $city=substr($tz,$spos+1); + $continents[$continent]=1; + if (!isset($cities[$continent])) $cities[$continent]=''; + $cities[$continent].=''; + } + } + $continents_html = ''; + $continents = array_keys($continents); + foreach($continents as $continent) + $continents_html.=''; + $cities_html = $cities[$pcontinent]; + $timezone_form = "Continent: "; + $timezone_form .= "    City:
"; + $timezone_js = "" ; + return array($timezone_form,$timezone_js); + } + return array('',''); +} +// Tells if a timezone is valid or not. +// If not valid, returns false. +// If system does not support timezone list, returns false. +function isTZvalid($continent,$city) +{ + $tz = $continent.'/'.$city; + if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr + { + if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone ? + return true; + } + return false; +} + +// Webservices (for use with jQuery/jQueryUI) +// eg. index.php?ws=tags&term=minecr +function processWS() +{ + if (empty($_GET['ws']) || empty($_GET['term'])) return; + $term = $_GET['term']; + $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). + header('Content-Type: application/json; charset=utf-8'); + // Search in tags (case insentitive, cumulative search) + if ($_GET['ws']=='tags') + { + $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") + $addtags=''; if ($tags) $addtags=implode(' ',$tags).' '; // We will pre-pend previous tags + $suggested=array(); + /* To speed up things, we store list of tags in session */ + if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); + foreach($_SESSION['tags'] as $key=>$value) + { + if (startsWith($key,$last,$case=false) && !in_array($key,$tags)) $suggested[$addtags.$key.' ']=0; + } + echo json_encode(array_keys($suggested)); + exit; + } + // Search a single tag (case sentitive, single tag search) + if ($_GET['ws']=='singletag') + { + /* To speed up things, we store list of tags in session */ + if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); + foreach($_SESSION['tags'] as $key=>$value) + { + if (startsWith($key,$term,$case=true)) $suggested[$key]=0; + } + echo json_encode(array_keys($suggested)); + exit; + } +} +function getAllTheme(){ + $allTheme = glob('tpl/*', GLOB_ONLYDIR); + foreach ($allTheme as $value) { + $themes[] = str_replace('tpl/', '', $value); + } + return $themes; +} +// Re-write configuration file according to globals. +// Requires some $GLOBALS to be set (login,hash,salt,title). +// If the config file cannot be saved, an error message is dislayed and the user is redirected to "Tools" menu. +// (otherwise, the function simply returns.) +function writeConfig() +{ + if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. + $config = "alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';'; + exit; + } +} + /* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. The following function takes the URL a link (eg. a flickr page) and return the proper thumbnail. From 35cc3582f0dc710a20c495b6d4c273f3a98772bf Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Sat, 16 Jan 2016 16:16:56 +0100 Subject: [PATCH 08/14] Logging: improve formatting to enable fail2ban parsing Fixes #436 Modifications: - remove calls to strval() on safe data - update the date format: 'Y/m/d_H:i:s' => 'Y/m/d H:i:s' Signed-off-by: VirtualTam --- index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.php b/index.php index 329b464..3c09e02 100644 --- a/index.php +++ b/index.php @@ -248,7 +248,7 @@ class pageCache // Log to text file function logm($message) { - $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; + $t = strval(date('Y/m/d H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt',$t,FILE_APPEND); } From a076447c7c262f470afd50328b7bea88143dff11 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Fri, 10 Jun 2016 16:00:08 +0200 Subject: [PATCH 09/14] Fix bad page title --- index.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/index.php b/index.php index 3c09e02..2827eac 100644 --- a/index.php +++ b/index.php @@ -2004,7 +2004,9 @@ function buildLinkList($PAGE,$LINKSDB) $PAGE->assign('next_page_url',$next_page_url); $PAGE->assign('page_current',$page); $PAGE->assign('page_max',$pagecount); - $PAGE->assign('pagetitle', $GLOBALS['pagetitle']); + if (!empty($GLOBALS['pagetitle']) && count($linkDisp) == 1) { + $PAGE->assign('pagetitle', $GLOBALS['pagetitle']); + } $PAGE->assign('result_count',count($linksToDisplay)); $PAGE->assign('search_type',$search_type); $PAGE->assign('search_crits',$search_crits); From 118f40d21e6eeb8b7f2daca08cd3fbec1901ff64 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Fri, 10 Jun 2016 16:26:53 +0200 Subject: [PATCH 10/14] Better indent --- index.php | 2918 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 1654 insertions(+), 1264 deletions(-) diff --git a/index.php b/index.php index 2827eac..498b886 100644 --- a/index.php +++ b/index.php @@ -31,14 +31,14 @@ $GLOBALS['config']['ENABLE_LOCALCACHE'] = true; // Enable Shaarli to store thumb $GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable. // Note: You must have publisher.php in the same directory as Shaarli index.php $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 $GLOBALS['config']['UPDATECHECK_URL'] = 'http://book.knah-tsaeb.org/shaarli_version.txt'; // Define last version of myShaarli $GLOBALS['config']['UPDATECHECK_DOWNLOAD'] = 'https://forge.leslibres.org/Knah-Tsaeb/MyShaarli'; -$GLOBALS['config']['ENABLE_UPDATECHECK'] = TRUE; +$GLOBALS['config']['ENABLE_UPDATECHECK'] = true; $GLOBALS['config']['externalThumbshot'] = ''; // Url for external thumbnailer // exemple : http://images.thumbshots.com/image.aspx?cid=dgdfgdfg&v=1&w=120&url= // the last param must be a url -$GLOBALS['config']['ENABLE_MARKDOWN'] = TRUE; +$GLOBALS['config']['ENABLE_MARKDOWN'] = true; $GLOBALS['config']['WALLABAG_URL'] = ''; $GLOBALS['config']['contactLink'] = ''; // Define link for contact Example : http://example.com/contact.php or mailo:contact@example.com $GLOBALS['config']['THEME'] = 'myShaarli'; @@ -46,94 +46,136 @@ $GLOBALS['config']['DATE_FORMAT'] = '%A %d %B %Y %T'; // see http://php.net/manu // ----------------------------------------------------------------------------------------------- // You should not touch below (or at your own risks !) // Optionnal config file. -if(file_exists($GLOBALS['config']['CONFIG_FILE'])){ - require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. +if (file_exists($GLOBALS['config']['CONFIG_FILE'])) { + require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. } -if (is_file($GLOBALS['config']['DATADIR'].'/options.php')){ - require($GLOBALS['config']['DATADIR'].'/options.php'); +if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) { + require $GLOBALS['config']['DATADIR'].'/options.php'; } -define('myShaarli_version','1.1.3'); -define('PHPPREFIX',''); // Suffix to encapsulate data in php code. +define('myShaarli_version', '1.1.3'); +define('PHPPREFIX', ''); // Suffix to encapsulate data in php code. // http://server.com/x/shaarli --> /shaarli/ -define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); +define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1 + strrpos($_SERVER['REQUEST_URI'], '/', 0))); // Force cookie path (but do not change lifetime) -$cookie=session_get_cookie_params(); -$cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; -session_set_cookie_params($cookie['lifetime'],$cookiedir,$_SERVER['HTTP_HOST']); // Set default cookie expiration and path. +$cookie = session_get_cookie_params(); +$cookiedir = ''; if (dirname($_SERVER['SCRIPT_NAME']) != '/') { + $cookiedir = dirname($_SERVER['SCRIPT_NAME']).'/'; + } +session_set_cookie_params($cookie['lifetime'], $cookiedir, $_SERVER['HTTP_HOST']); // Set default cookie expiration and path. // Set session parameters on server side. -define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired. +define('INACTIVITY_TIMEOUT', 3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired. ini_set('session.use_cookies', 1); // Use cookies to store session. ini_set('session.use_only_cookies', 1); // Force cookies for session (phpsessionID forbidden in URL) ini_set('session.use_trans_sid', false); // Prevent php to use sessionID in URL if cookies are disabled. session_name('shaarli'); -if (session_id() == '') session_start(); // Start session if needed (Some server auto-start sessions). +if (session_id() == '') { + session_start(); +} // Start session if needed (Some server auto-start sessions). // PHP Settings -ini_set('max_input_time','60'); // High execution time in case of problematic imports/exports. +ini_set('max_input_time', '60'); // High execution time in case of problematic imports/exports. ini_set('memory_limit', '128M'); // Try to set max upload file size and read (May not work on some hosts). ini_set('post_max_size', '16M'); ini_set('upload_max_filesize', '16M'); checkphpversion(); -error_reporting(E_ALL^E_WARNING); // See all error except warnings. +error_reporting(E_ALL ^ E_WARNING); // See all error except warnings. //error_reporting(-1); // See all errors (for debugging only) -if($GLOBALS['config']['ENABLE_MARKDOWN'] === TRUE){ - include 'inc/Parsedown.php'; +if ($GLOBALS['config']['ENABLE_MARKDOWN'] === true) { + include 'inc/Parsedown.php'; } -include "inc/rain.tpl.class.php"; //include Rain TPL +include 'inc/rain.tpl.class.php'; //include Rain TPL raintpl::$tpl_dir = 'tpl/'.$GLOBALS['config']['THEME'].'/'; // template directory -if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } -raintpl::$cache_dir = "tmp/"; // cache directory +if (!is_dir('tmp')) { + mkdir('tmp', 0705); + chmod('tmp', 0705); +} +raintpl::$cache_dir = 'tmp/'; // cache directory ob_start(); // Output buffering for the page cache. - // In case stupid admin has left magic_quotes enabled in php.ini: -if (get_magic_quotes_gpc()) -{ - function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; } +if (get_magic_quotes_gpc()) { + function stripslashes_deep($value) + { + $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); + + return $value; + } $_POST = array_map('stripslashes_deep', $_POST); $_GET = array_map('stripslashes_deep', $_GET); $_COOKIE = array_map('stripslashes_deep', $_COOKIE); } // Prevent caching on client side or proxy: (yes, it's ugly) -header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); // Directories creations (Note that your web host may require differents rights than 705.) -if (!is_writable(realpath(dirname(__FILE__)))) die('
ERROR: Shaarli does not have the right to write in its own directory ('.realpath(dirname(__FILE__)).').
'); -if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } -if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } // For RainTPL temporary files. -if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. +if (!is_writable(realpath(dirname(__FILE__)))) { + die('
ERROR: Shaarli does not have the right to write in its own directory ('.realpath(dirname(__FILE__)).').
'); +} +if (!is_dir($GLOBALS['config']['DATADIR'])) { + mkdir($GLOBALS['config']['DATADIR'], 0705); + chmod($GLOBALS['config']['DATADIR'], 0705); +} +if (!is_dir('tmp')) { + mkdir('tmp', 0705); + chmod('tmp', 0705); +} // For RainTPL temporary files. +if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { + file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess', "Allow from none\nDeny from all\n"); +} // Protect data files. // Second check to see if Shaarli can write in its directory, because on some hosts is_writable() is not reliable. -if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) die('
ERROR: Shaarli does not have the right to write in its data directory ('.realpath($GLOBALS['config']['DATADIR']).').
'); -if ($GLOBALS['config']['ENABLE_LOCALCACHE']) -{ - if (!is_dir($GLOBALS['config']['CACHEDIR'])) { mkdir($GLOBALS['config']['CACHEDIR'],0705); chmod($GLOBALS['config']['CACHEDIR'],0705); } - if (!is_file($GLOBALS['config']['CACHEDIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['CACHEDIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. +if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { + die('
ERROR: Shaarli does not have the right to write in its data directory ('.realpath($GLOBALS['config']['DATADIR']).').
'); +} +if ($GLOBALS['config']['ENABLE_LOCALCACHE']) { + if (!is_dir($GLOBALS['config']['CACHEDIR'])) { + mkdir($GLOBALS['config']['CACHEDIR'], 0705); + chmod($GLOBALS['config']['CACHEDIR'], 0705); + } + if (!is_file($GLOBALS['config']['CACHEDIR'].'/.htaccess')) { + file_put_contents($GLOBALS['config']['CACHEDIR'].'/.htaccess', "Allow from none\nDeny from all\n"); + } // Protect data files. } // Handling of old config file which do not have the new parameters. -if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl()); -if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); -if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; -if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; -if (empty($GLOBALS['disablejquery'])) $GLOBALS['disablejquery']=false; -if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false; -if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?'; +if (empty($GLOBALS['title'])) { + $GLOBALS['title'] = 'Shared links on '.htmlspecialchars(indexUrl()); +} +if (empty($GLOBALS['timezone'])) { + $GLOBALS['timezone'] = date_default_timezone_get(); +} +if (empty($GLOBALS['redirector'])) { + $GLOBALS['redirector'] = ''; +} +if (empty($GLOBALS['disablesessionprotection'])) { + $GLOBALS['disablesessionprotection'] = false; +} +if (empty($GLOBALS['disablejquery'])) { + $GLOBALS['disablejquery'] = false; +} +if (empty($GLOBALS['privateLinkByDefault'])) { + $GLOBALS['privateLinkByDefault'] = false; +} +if (empty($GLOBALS['titleLink'])) { + $GLOBALS['titleLink'] = '?'; +} // Run config screen if first run: -if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); +if (!is_file($GLOBALS['config']['CONFIG_FILE'])) { + install(); +} // a token depending of deployment salt, user password, and the current ip -define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt'])); +define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER['REMOTE_ADDR'].$GLOBALS['salt'])); autoLocale(); // Sniff browser language and set date format accordingly. header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. @@ -141,8 +183,7 @@ header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper int // Check php version function checkphpversion() { - if (version_compare(PHP_VERSION, '5.1.0') < 0) - { + if (version_compare(PHP_VERSION, '5.1.0') < 0) { header('Content-Type: text/plain; charset=utf-8'); echo 'Your server supports php '.PHP_VERSION.'. Shaarli requires at least php 5.1.0, and thus cannot run. Sorry.'; exit; @@ -155,37 +196,37 @@ function checkphpversion() // other= the available version. function checkUpdate() { - if (!isLoggedIn()){ - return false; // Do not check versions for visitors. + if (!isLoggedIn()) { + return false; // Do not check versions for visitors. } - if (empty($GLOBALS['config']['ENABLE_UPDATECHECK'])){ - return false; // Do not check if the user doesn't want to. + if (empty($GLOBALS['config']['ENABLE_UPDATECHECK'])) { + return false; // Do not check if the user doesn't want to. } // Get latest version number at most once a day. - if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])url = $url; $this->filename = $GLOBALS['config']['PAGECACHE'].'/'.sha1($url).'.cache'; @@ -210,52 +251,60 @@ class pageCache // returns the cached version (otherwise, return null). public function cachedVersion() { - if (!$this->shouldBeCached) return null; - if (is_file($this->filename)) { return file_get_contents($this->filename); exit; } - return null; + if (!$this->shouldBeCached) { + return; + } + if (is_file($this->filename)) { + return file_get_contents($this->filename); + exit; + } + + return; } // Put a page in the cache. public function cache($page) { - if (!$this->shouldBeCached) return; - if (!is_dir($GLOBALS['config']['PAGECACHE'])) { mkdir($GLOBALS['config']['PAGECACHE'],0705); chmod($GLOBALS['config']['PAGECACHE'],0705); } - file_put_contents($this->filename,$page); + if (!$this->shouldBeCached) { + return; + } + if (!is_dir($GLOBALS['config']['PAGECACHE'])) { + mkdir($GLOBALS['config']['PAGECACHE'], 0705); + chmod($GLOBALS['config']['PAGECACHE'], 0705); + } + file_put_contents($this->filename, $page); } // Purge the whole cache. // (call with pageCache::purgeCache()) public static function purgeCache() { - if (is_dir($GLOBALS['config']['PAGECACHE'])) - { + if (is_dir($GLOBALS['config']['PAGECACHE'])) { $handler = opendir($GLOBALS['config']['PAGECACHE']); - if ($handler!==false) - { - while (($filename = readdir($handler))!==false) - { - if (endsWith($filename,'.cache')) { unlink($GLOBALS['config']['PAGECACHE'].'/'.$filename); } + if ($handler !== false) { + while (($filename = readdir($handler)) !== false) { + if (endsWith($filename, '.cache')) { + unlink($GLOBALS['config']['PAGECACHE'].'/'.$filename); + } } closedir($handler); } } } - } - // ----------------------------------------------------------------------------------------------- // Log to text file function logm($message) { - $t = strval(date('Y/m/d H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; - file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt',$t,FILE_APPEND); + $t = strval(date('Y/m/d H:i:s')).' - '.$_SERVER['REMOTE_ADDR'].' - '.strval($message)."\n"; + file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt', $t, FILE_APPEND); } // Same as nl2br(), but escapes < and > function nl2br_escaped($html) { - return str_replace('>','>',str_replace('<','<',nl2br($html))); + return str_replace('>', '>', str_replace('<', '<', nl2br($html))); } /* Returns the small hash of a string, using RFC 4648 base64url format @@ -269,7 +318,8 @@ function nl2br_escaped($html) */ function smallHash($text) { - $t = rtrim(base64_encode(hash('crc32',$text,true)),'='); + $t = rtrim(base64_encode(hash('crc32', $text, true)), '='); + return strtr($t, '+/', '-_'); } @@ -278,15 +328,15 @@ function smallHash($text) function text2clickable($url) { $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']; - return preg_replace('!(((?:https?|ftp|file)://|apt:|magnet:)\S+[[:alnum:]]/?)!si','$1',$url); + + return preg_replace('!(((?:https?|ftp|file)://|apt:|magnet:)\S+[[:alnum:]]/?)!si', '$1', $url); } // This function inserts   where relevant so that multiple spaces are properly displayed in HTML // even in the absence of
  (This is used in description to keep text formatting)
 function keepMultipleSpaces($text)
 {
-    return str_replace('  ','  ',$text);
-
+    return str_replace('  ', '  ', $text);
 }
 // ------------------------------------------------------------------------------------------
 // Sniff browser language to display dates in the right format automatically.
@@ -294,14 +344,15 @@ function keepMultipleSpaces($text)
 function autoLocale()
 {
     $attempts = array('en_US'); // Default if browser does not send HTTP_ACCEPT_LANGUAGE
-    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // e.g. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3"
-    {   // (It's a bit crude, but it works very well. Preferred language is always presented first.)
-        if (preg_match('/([a-z]{2})-?([a-z]{2})?/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) {
-            $loc = $matches[1] . (!empty($matches[2]) ? '_' . strtoupper($matches[2]) : '');
+    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+        // e.g. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3"
+   // (It's a bit crude, but it works very well. Preferred language is always presented first.)
+        if (preg_match('/([a-z]{2})-?([a-z]{2})?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches)) {
+            $loc = $matches[1].(!empty($matches[2]) ? '_'.strtoupper($matches[2]) : '');
             $attempts = array($loc.'.UTF-8', $loc, str_replace('_', '-', $loc).'.UTF-8', str_replace('_', '-', $loc),
-                $loc . '_' . strtoupper($loc).'.UTF-8', $loc . '_' . strtoupper($loc),
-                $loc . '_' . $loc.'.UTF-8', $loc . '_' . $loc, $loc . '-' . strtoupper($loc).'.UTF-8',
-                $loc . '-' . strtoupper($loc), $loc . '-' . $loc.'.UTF-8', $loc . '-' . $loc);
+                $loc.'_'.strtoupper($loc).'.UTF-8', $loc.'_'.strtoupper($loc),
+                $loc.'_'.$loc.'.UTF-8', $loc.'_'.$loc, $loc.'-'.strtoupper($loc).'.UTF-8',
+                $loc.'-'.strtoupper($loc), $loc.'-'.$loc.'.UTF-8', $loc.'-'.$loc, );
         }
     }
     setlocale(LC_TIME, $attempts);  // LC_TIME = Set local for date/time format only.
@@ -310,17 +361,18 @@ function autoLocale()
 // ------------------------------------------------------------------------------------------
 // PubSubHubbub protocol support (if enabled)  [UNTESTED]
 // (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ )
-if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) include './publisher.php';
+if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) {
+    include './publisher.php';
+}
 function pubsubhub()
 {
-    if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
-    {
-       $p = new Publisher($GLOBALS['config']['PUBSUBHUB_URL']);
-       $topic_url = array (
+    if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) {
+        $p = new Publisher($GLOBALS['config']['PUBSUBHUB_URL']);
+        $topic_url = array(
                        indexUrl().'?do=atom',
-                       indexUrl().'?do=rss'
+                       indexUrl().'?do=rss',
                     );
-       $p->publish_update($topic_url);
+        $p->publish_update($topic_url);
     }
 }
 
@@ -330,155 +382,191 @@ function pubsubhub()
 // Returns the IP address of the client (Used to prevent session cookie hijacking.)
 function allIPs()
 {
-    $ip = $_SERVER["REMOTE_ADDR"];
+    $ip = $_SERVER['REMOTE_ADDR'];
     // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy.
-    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; }
-    if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; }
+    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+        $ip = $ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR'];
+    }
+    if (isset($_SERVER['HTTP_CLIENT_IP'])) {
+        $ip = $ip.'_'.$_SERVER['HTTP_CLIENT_IP'];
+    }
+
     return $ip;
 }
 
-function fillSessionInfo() {
-	$_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // generate unique random number (different than phpsessionid)
-	$_SESSION['ip']=allIPs();                // We store IP address(es) of the client to make sure session is not hijacked.
-	$_SESSION['username']=$GLOBALS['login'];
-	$_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT;  // Set session expiration.
+function fillSessionInfo()
+{
+    $_SESSION['uid'] = sha1(uniqid('', true).'_'.mt_rand()); // generate unique random number (different than phpsessionid)
+    $_SESSION['ip'] = allIPs();                // We store IP address(es) of the client to make sure session is not hijacked.
+    $_SESSION['username'] = $GLOBALS['login'];
+    $_SESSION['expires_on'] = time() + INACTIVITY_TIMEOUT;  // Set session expiration.
 }
 
 // Check that user/password is correct.
-function check_auth($login,$password)
+function check_auth($login, $password)
 {
     $hash = sha1($password.$login.$GLOBALS['salt']);
-    if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash'])
-    {   // Login/password is correct.
-		fillSessionInfo();
+    if ($login == $GLOBALS['login'] && $hash == $GLOBALS['hash']) {   // Login/password is correct.
+        fillSessionInfo();
         logm('Login successful');
-        return True;
+
+        return true;
     }
     logm('Login failed for user '.$login);
-    return False;
+
+    return false;
 }
 
 // Returns true if the user is logged in.
 function isLoggedIn()
 {
-    if ($GLOBALS['config']['OPEN_SHAARLI']) return true;
+    if ($GLOBALS['config']['OPEN_SHAARLI']) {
+        return true;
+    }
 
-    if (!isset($GLOBALS['login'])) return false;  // Shaarli is not configured yet.
+    if (!isset($GLOBALS['login'])) {
+        return false;
+    }  // Shaarli is not configured yet.
 
-	if (@$_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN)
-	{
-		fillSessionInfo();
-		return true;
-	}
+    if (@$_COOKIE['shaarli_staySignedIn'] === STAY_SIGNED_IN_TOKEN) {
+        fillSessionInfo();
+
+        return true;
+    }
     // If session does not exist on server side, or IP address has changed, or session has expired, logout.
-    if (empty($_SESSION['uid']) || ($GLOBALS['disablesessionprotection']==false && $_SESSION['ip']!=allIPs()) || time()>=$_SESSION['expires_on'])
-    {
+    if (empty($_SESSION['uid']) || ($GLOBALS['disablesessionprotection'] == false && $_SESSION['ip'] != allIPs()) || time() >= $_SESSION['expires_on']) {
         logout();
+
         return false;
     }
-    if (!empty($_SESSION['longlastingsession']))  $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked.
-    else $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date.
+    if (!empty($_SESSION['longlastingsession'])) {
+        $_SESSION['expires_on'] = time() + $_SESSION['longlastingsession'];
+    } // In case of "Stay signed in" checked.
+    else {
+        $_SESSION['expires_on'] = time() + INACTIVITY_TIMEOUT;
+    } // Standard session expiration date.
 
     return true;
 }
 
 // Force logout.
-function logout() {
-  if (isset($_SESSION)) {
-    unset($_SESSION['uid'], $_SESSION['ip'], $_SESSION['username'], $_SESSION['privateonly']);
-  }
-  setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH);
+function logout()
+{
+    if (isset($_SESSION)) {
+        unset($_SESSION['uid'], $_SESSION['ip'], $_SESSION['username'], $_SESSION['privateonly']);
+    }
+    setcookie('shaarli_staySignedIn', false, 0, WEB_PATH);
 }
 
-
 // ------------------------------------------------------------------------------------------
 // Brute force protection system
 // Several consecutive failed logins will ban the IP address for 30 minutes.
-if (!is_file($GLOBALS['config']['IPBANS_FILENAME'])) file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "array(),'BANS'=>array()),true).";\n?>");
+if (!is_file($GLOBALS['config']['IPBANS_FILENAME'])) {
+    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], " array(), 'BANS' => array()), true).";\n?>");
+}
 include $GLOBALS['config']['IPBANS_FILENAME'];
 // Signal a failed login. Will ban the IP if too many failures:
 function ban_loginFailed()
 {
-    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
-    if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0;
-    $gb['FAILURES'][$ip]++;
-    if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1))
-    {
-        $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION'];
+    $ip = $_SERVER['REMOTE_ADDR'];
+    $gb = $GLOBALS['IPBANS'];
+    if (!isset($gb['FAILURES'][$ip])) {
+        $gb['FAILURES'][$ip] = 0;
+    }
+    ++$gb['FAILURES'][$ip];
+    if ($gb['FAILURES'][$ip] > ($GLOBALS['config']['BAN_AFTER'] - 1)) {
+        $gb['BANS'][$ip] = time() + $GLOBALS['config']['BAN_DURATION'];
         logm('IP address banned from login');
     }
     $GLOBALS['IPBANS'] = $gb;
-    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
+    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
 }
 
 // Signals a successful login. Resets failed login counter.
 function ban_loginOk()
 {
-    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
-    unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
+    $ip = $_SERVER['REMOTE_ADDR'];
+    $gb = $GLOBALS['IPBANS'];
+    unset($gb['FAILURES'][$ip]);
+    unset($gb['BANS'][$ip]);
     $GLOBALS['IPBANS'] = $gb;
-    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
+    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
 }
 
 // Checks if the user CAN login. If 'true', the user can try to login.
 function ban_canLogin()
 {
-    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
-    if (isset($gb['BANS'][$ip]))
-    {
+    $ip = $_SERVER['REMOTE_ADDR'];
+    $gb = $GLOBALS['IPBANS'];
+    if (isset($gb['BANS'][$ip])) {
         // User is banned. Check if the ban has expired:
-        if ($gb['BANS'][$ip]<=time())
-        {   // Ban expired, user can try to login again.
+        if ($gb['BANS'][$ip] <= time()) {   // Ban expired, user can try to login again.
             logm('Ban lifted.');
-            unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
-            file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
+            unset($gb['FAILURES'][$ip]);
+            unset($gb['BANS'][$ip]);
+            file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
+
             return true; // Ban has expired, user can login.
         }
+
         return false; // User is banned.
     }
+
     return true; // User is not banned.
 }
 
 // ------------------------------------------------------------------------------------------
 // Process login form: Check if login/password is correct.
-if (isset($_POST['login']))
-{
-    if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.');
-    if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password'])))
-    {   // Login/password is ok.
+if (isset($_POST['login'])) {
+    if (!ban_canLogin()) {
+        die('I said: NO. You are banned for the moment. Go away.');
+    }
+    if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password']))) {   // Login/password is ok.
         ban_loginOk();
         // If user wants to keep the session cookie even after the browser closes:
-        if (!empty($_POST['longlastingsession']))
-        {
-			setcookie('shaarli_staySignedIn', STAY_SIGNED_IN_TOKEN, time()+31536000, WEB_PATH);
-            $_SESSION['longlastingsession']=31536000;  // (31536000 seconds = 1 year)
-            $_SESSION['expires_on']=time()+$_SESSION['longlastingsession'];  // Set session expiration on server-side.
+        if (!empty($_POST['longlastingsession'])) {
+            setcookie('shaarli_staySignedIn', STAY_SIGNED_IN_TOKEN, time() + 31536000, WEB_PATH);
+            $_SESSION['longlastingsession'] = 31536000;  // (31536000 seconds = 1 year)
+            $_SESSION['expires_on'] = time() + $_SESSION['longlastingsession'];  // Set session expiration on server-side.
 
-            $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/';
-            session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['HTTP_HOST']); // Set session cookie expiration on client side
+            $cookiedir = '';
+            if (dirname($_SERVER['SCRIPT_NAME']) != '/') {
+                $cookiedir = dirname($_SERVER['SCRIPT_NAME']).'/';
+            }
+            session_set_cookie_params($_SESSION['longlastingsession'], $cookiedir, $_SERVER['HTTP_HOST']); // Set session cookie expiration on client side
             // Note: Never forget the trailing slash on the cookie path !
             session_regenerate_id(true);  // Send cookie with new expiration date to browser.
-        }
-        else // Standard session expiration (=when browser closes)
-        {
-            $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/';
-            session_set_cookie_params(0,$cookiedir,$_SERVER['HTTP_HOST']); // 0 means "When browser closes"
+        } else {
+            // Standard session expiration (=when browser closes)
+
+            $cookiedir = '';
+            if (dirname($_SERVER['SCRIPT_NAME']) != '/') {
+                $cookiedir = dirname($_SERVER['SCRIPT_NAME']).'/';
+            }
+            session_set_cookie_params(0, $cookiedir, $_SERVER['HTTP_HOST']); // 0 means "When browser closes"
             session_regenerate_id(true);
         }
         // Optional redirect after login:
-        if (isset($_GET['post'])) { header('Location: ?post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); exit; }
-        if (isset($_POST['returnurl']))
-        {
-            if (endsWith($_POST['returnurl'],'?do=login')) { header('Location: ?'); exit; } // Prevent loops over login screen.
-            header('Location: '.$_POST['returnurl']); exit;
+        if (isset($_GET['post'])) {
+            header('Location: ?post='.urlencode($_GET['post']).(!empty($_GET['title']) ? '&title='.urlencode($_GET['title']) : '').(!empty($_GET['source']) ? '&source='.urlencode($_GET['source']) : ''));
+            exit;
         }
-        header('Location: ?'); exit;
-    }
-    else
-    {
+        if (isset($_POST['returnurl'])) {
+            if (endsWith($_POST['returnurl'], '?do=login')) {
+                header('Location: ?');
+                exit;
+            } // Prevent loops over login screen.
+            header('Location: '.$_POST['returnurl']);
+            exit;
+        }
+        header('Location: ?');
+        exit;
+    } else {
         ban_loginFailed();
         $redir = '';
-        if (isset($_GET['post'])) { $redir = '&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'');  }
+        if (isset($_GET['post'])) {
+            $redir = '&post='.urlencode($_GET['post']).(!empty($_GET['title']) ? '&title='.urlencode($_GET['title']) : '').(!empty($_GET['source']) ? '&source='.urlencode($_GET['source']) : '');
+        }
         echo ''; // Redirect to login screen.
         exit;
     }
@@ -488,49 +576,56 @@ if (isset($_POST['login']))
 // Misc utility functions:
 
 // Try to get just domain for @via
-function getJustDomain($url){
+function getJustDomain($url)
+{
     $parts = parse_url($url);
+
     return trim($parts['host']);
-    }
+}
 
 // Returns the server URL (including port and http/https), without path.
 // eg. "http://myserver.com:8080"
 // You can append $_SERVER['SCRIPT_NAME'] to get the current script URL.
 function serverUrl()
 {
-    $https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
-    $serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
-    return 'http'.($https?'s':'').'://'.$_SERVER['HTTP_HOST'].$serverport;
+    $https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) == 'on')) || $_SERVER['SERVER_PORT'] == '443'; // HTTPS detection.
+    $serverport = ($_SERVER['SERVER_PORT'] == '80' || ($https && $_SERVER['SERVER_PORT'] == '443') ? '' : ':'.$_SERVER['SERVER_PORT']);
+
+    return 'http'.($https ? 's' : '').'://'.$_SERVER['HTTP_HOST'].$serverport;
 }
 
 // Returns the absolute URL of current script, without the query.
 // (eg. http://sebsauvage.net/links/)
 function indexUrl()
 {
-    $scriptname = $_SERVER["SCRIPT_NAME"];
+    $scriptname = $_SERVER['SCRIPT_NAME'];
     // If the script is named 'index.php', we remove it (for better looking URLs,
     // eg. http://mysite.com/shaarli/?abcde instead of http://mysite.com/shaarli/index.php?abcde)
-    if (endswith($scriptname,'index.php')) $scriptname = substr($scriptname,0,strlen($scriptname)-9);
-    return serverUrl() . $scriptname;
+    if (endswith($scriptname, 'index.php')) {
+        $scriptname = substr($scriptname, 0, strlen($scriptname) - 9);
+    }
+
+    return serverUrl().$scriptname;
 }
 
 // Returns the absolute URL of current script, WITH the query.
 // (eg. http://sebsauvage.net/links/?toto=titi&spamspamspam=humbug)
 function pageUrl()
 {
-    return indexUrl().(!empty($_SERVER["QUERY_STRING"]) ? '?'.$_SERVER["QUERY_STRING"] : '');
+    return indexUrl().(!empty($_SERVER['QUERY_STRING']) ? '?'.$_SERVER['QUERY_STRING'] : '');
 }
 
 // Convert post_max_size/upload_max_filesize (eg.'16M') parameters to bytes.
 function return_bytes($val)
 {
-    $val = trim($val); $last=strtolower($val[strlen($val)-1]);
-    switch($last)
-    {
+    $val = trim($val);
+    $last = strtolower($val[strlen($val) - 1]);
+    switch ($last) {
         case 'g': $val *= 1024;
         case 'm': $val *= 1024;
         case 'k': $val *= 1024;
     }
+
     return $val;
 }
 
@@ -541,23 +636,29 @@ function getMaxFileSize()
     $size1 = return_bytes(ini_get('post_max_size'));
     $size2 = return_bytes(ini_get('upload_max_filesize'));
     // Return the smaller of two:
-    $maxsize = min($size1,$size2);
+    $maxsize = min($size1, $size2);
     // FIXME: Then convert back to readable notations ? (eg. 2M instead of 2000000)
     return $maxsize;
 }
 
 // Tells if a string start with a substring or not.
-function startsWith($haystack,$needle,$case=true)
+function startsWith($haystack, $needle, $case = true)
 {
-    if($case){return (strcmp(substr($haystack, 0, strlen($needle)),$needle)===0);}
-    return (strcasecmp(substr($haystack, 0, strlen($needle)),$needle)===0);
+    if ($case) {
+        return strcmp(substr($haystack, 0, strlen($needle)), $needle) === 0;
+    }
+
+    return strcasecmp(substr($haystack, 0, strlen($needle)), $needle) === 0;
 }
 
 // Tells if a string ends with a substring or not.
-function endsWith($haystack,$needle,$case=true)
+function endsWith($haystack, $needle, $case = true)
 {
-    if($case){return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);}
-    return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);
+    if ($case) {
+        return strcmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0;
+    }
+
+    return strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0;
 }
 
 /*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a timestamp (Unix epoch)
@@ -565,23 +666,24 @@ function endsWith($haystack,$needle,$case=true)
     PS: I could have used strptime(), but it does not exist on Windows. I'm too kind. */
 function linkdate2timestamp($linkdate)
 {
-    $Y=$M=$D=$h=$m=$s=0;
-    sscanf($linkdate,'%4d%2d%2d_%2d%2d%2d',$Y,$M,$D,$h,$m,$s);
-    return mktime($h,$m,$s,$M,$D,$Y);
+    $Y = $M = $D = $h = $m = $s = 0;
+    sscanf($linkdate, '%4d%2d%2d_%2d%2d%2d', $Y, $M, $D, $h, $m, $s);
+
+    return mktime($h, $m, $s, $M, $D, $Y);
 }
 
 /*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a RFC822 date.
     (used to build the pubDate attribute in RSS feed.)  */
 function linkdate2rfc822($linkdate)
 {
-    return date('r',linkdate2timestamp($linkdate)); // 'r' is for RFC822 date format.
+    return date('r', linkdate2timestamp($linkdate)); // 'r' is for RFC822 date format.
 }
 
 /*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a ISO 8601 date.
     (used to build the updated tags in ATOM feed.)  */
 function linkdate2iso8601($linkdate)
 {
-    return date('c',linkdate2timestamp($linkdate)); // 'c' is for ISO 8601 date format.
+    return date('c', linkdate2timestamp($linkdate)); // 'c' is for ISO 8601 date format.
 }
 
 /*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a localized date format.
@@ -589,28 +691,28 @@ function linkdate2iso8601($linkdate)
     The date format is automatically chosen according to locale/languages sniffed from browser headers (see autoLocale()). */
 function linkdate2locale($linkdate)
 {
-  if(empty($GLOBALS['config']['DATE_FORMAT'])){
-    $GLOBALS['config']['DATE_FORMAT'] = '%c';
-  }
-    return strftime($GLOBALS['config']['DATE_FORMAT'],linkdate2timestamp($linkdate)); // %c is for automatic date format according to locale.
+    if (empty($GLOBALS['config']['DATE_FORMAT'])) {
+        $GLOBALS['config']['DATE_FORMAT'] = '%c';
+    }
+
+    return strftime($GLOBALS['config']['DATE_FORMAT'], linkdate2timestamp($linkdate)); // %c is for automatic date format according to locale.
     // Note that if you use a local which is not installed on your webserver,
     // the date will not be displayed in the chosen locale, but probably in US notation.
 }
 
 // Parse HTTP response headers and return an associative array.
-function http_parse_headers_shaarli( $headers )
+function http_parse_headers_shaarli($headers)
 {
-    $res=array();
-    foreach($headers as $header)
-    {
-        $i = strpos($header,': ');
-        if ($i!==false)
-        {
-            $key=substr($header,0,$i);
-            $value=substr($header,$i+2,strlen($header)-$i-2);
-            $res[$key]=$value;
+    $res = array();
+    foreach ($headers as $header) {
+        $i = strpos($header, ': ');
+        if ($i !== false) {
+            $key = substr($header, 0, $i);
+            $value = substr($header, $i + 2, strlen($header) - $i - 2);
+            $res[$key] = $value;
         }
     }
+
     return $res;
 }
 
@@ -626,21 +728,23 @@ function http_parse_headers_shaarli( $headers )
              else
                  echo 'There was an error: '.htmlspecialchars($httpstatus)
 */
-function getHTTP($url,$timeout=30)
+function getHTTP($url, $timeout = 30)
 {
-    try
-    {
-        $options = array('http'=>array('method'=>'GET','timeout' => $timeout, 'user_agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:23.0) Gecko/20100101 Firefox/23.0')); // Force network timeout
+    try {
+        $options = array('http' => array('method' => 'GET', 'timeout' => $timeout, 'user_agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:23.0) Gecko/20100101 Firefox/23.0')); // Force network timeout
         $context = stream_context_create($options);
-        $data=file_get_contents($url,false,$context,-1, 4000000); // We download at most 4 Mb from source.
-        if (!$data) { return array('HTTP Error',array(),''); }
-        $httpStatus=$http_response_header[0]; // eg. "HTTP/1.1 200 OK"
-        $responseHeaders=http_parse_headers_shaarli($http_response_header);
-        return array($httpStatus,$responseHeaders,$data);
-    }
-    catch (Exception $e)  // getHTTP *can* fail silentely (we don't care if the title cannot be fetched)
-    {
-        return array($e->getMessage(),'','');
+        $data = file_get_contents($url, false, $context, -1, 4000000); // We download at most 4 Mb from source.
+        if (!$data) {
+            return array('HTTP Error', array(), '');
+        }
+        $httpStatus = $http_response_header[0]; // eg. "HTTP/1.1 200 OK"
+        $responseHeaders = http_parse_headers_shaarli($http_response_header);
+
+        return array($httpStatus, $responseHeaders, $data);
+    } catch (Exception $e) {
+        // getHTTP *can* fail silentely (we don't care if the title cannot be fetched)
+
+        return array($e->getMessage(), '', '');
     }
 }
 
@@ -648,19 +752,21 @@ function getHTTP($url,$timeout=30)
 // (Returns an empty string if not found.)
 function html_extract_title($html)
 {
-  return preg_match('!(.*?)!is', $html, $matches) ? trim(str_replace("\n",' ', $matches[1])) : '' ;
+    return preg_match('!(.*?)!is', $html, $matches) ? trim(str_replace("\n", ' ', $matches[1])) : '';
 }
 
 // ------------------------------------------------------------------------------------------
 // Token management for XSRF protection
 // Token should be used in any form which acts on data (create,update,delete,import...).
-if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array();  // Token are attached to the session.
+if (!isset($_SESSION['tokens'])) {
+    $_SESSION['tokens'] = array();
+}  // Token are attached to the session.
 
 // Returns a token.
 function getToken()
 {
-    $rnd = sha1(uniqid('',true).'_'.mt_rand().$GLOBALS['salt']);  // We generate a random string.
-    $_SESSION['tokens'][$rnd]=1;  // Store it on the server side.
+    $rnd = sha1(uniqid('', true).'_'.mt_rand().$GLOBALS['salt']);  // We generate a random string.
+    $_SESSION['tokens'][$rnd] = 1;  // Store it on the server side.
     return $rnd;
 }
 
@@ -668,11 +774,11 @@ function getToken()
 // true=token is ok.
 function tokenOk($token)
 {
-    if (isset($_SESSION['tokens'][$token]))
-    {
+    if (isset($_SESSION['tokens'][$token])) {
         unset($_SESSION['tokens'][$token]); // Token is used: destroy it.
         return true; // Token is ok.
     }
+
     return false; // Wrong token, or already used.
 }
 
@@ -688,45 +794,59 @@ class pageBuilder
 {
     private $tpl; // RainTPL template
 
-    function __construct()
+    public function __construct()
     {
-        $this->tpl=false;
+        $this->tpl = false;
     }
 
     private function initialize()
     {
-        $this->tpl = new RainTPL;
-        $this->tpl->assign('theme',$GLOBALS['config']['THEME']);
-        $this->tpl->assign('newversion',checkUpdate());
-        $this->tpl->assign('feedurl',htmlspecialchars(indexUrl()));
-        $searchcrits=''; // Search criteria
-        if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']);
-        elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']);
-        $this->tpl->assign('searchcrits',$searchcrits);
-        $this->tpl->assign('source',indexUrl());
-        $this->tpl->assign('version',myShaarli_version);
-        $this->tpl->assign('scripturl',indexUrl());
-        $this->tpl->assign('pagetitle','Shaarli');
-        $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ?
-        if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
-        if (!empty($GLOBALS['titleLink'])) $this->tpl->assign('titleLink',$GLOBALS['titleLink']);
-        if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
-        $this->tpl->assign('shaarlititle',empty($GLOBALS['title']) ? 'Shaarli': $GLOBALS['title'] );
+        $this->tpl = new RainTPL();
+        $this->tpl->assign('theme', $GLOBALS['config']['THEME']);
+        $this->tpl->assign('newversion', checkUpdate());
+        $this->tpl->assign('feedurl', htmlspecialchars(indexUrl()));
+        $searchcrits = ''; // Search criteria
+        if (!empty($_GET['searchtags'])) {
+            $searchcrits .= '&searchtags='.urlencode($_GET['searchtags']);
+        } elseif (!empty($_GET['searchterm'])) {
+            $searchcrits .= '&searchterm='.urlencode($_GET['searchterm']);
+        }
+        $this->tpl->assign('searchcrits', $searchcrits);
+        $this->tpl->assign('source', indexUrl());
+        $this->tpl->assign('version', myShaarli_version);
+        $this->tpl->assign('scripturl', indexUrl());
+        $this->tpl->assign('pagetitle', 'Shaarli');
+        $this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links ?
+        if (!empty($GLOBALS['title'])) {
+            $this->tpl->assign('pagetitle', $GLOBALS['title']);
+        }
+        if (!empty($GLOBALS['titleLink'])) {
+            $this->tpl->assign('titleLink', $GLOBALS['titleLink']);
+        }
+        if (!empty($GLOBALS['pagetitle'])) {
+            $this->tpl->assign('pagetitle', $GLOBALS['pagetitle']);
+        }
+        $this->tpl->assign('shaarlititle', empty($GLOBALS['title']) ? 'Shaarli' : $GLOBALS['title']);
+
         return;
     }
 
     // The following assign() method is basically the same as RainTPL (except that it's lazy)
-    public function assign($what,$where)
+    public function assign($what, $where)
     {
-        if ($this->tpl===false) $this->initialize(); // Lazy initialization
-        $this->tpl->assign($what,$where);
+        if ($this->tpl === false) {
+            $this->initialize();
+        } // Lazy initialization
+        $this->tpl->assign($what, $where);
     }
 
     // Render a specific page (using a template).
     // eg. pb.renderPage('picwall')
     public function renderPage($page)
     {
-        if ($this->tpl===false) $this->initialize(); // Lazy initialization
+        if ($this->tpl === false) {
+            $this->initialize();
+        } // Lazy initialization
           $this->tpl->draw($page);
     }
 }
@@ -762,7 +882,7 @@ class linkdb implements Iterator, Countable, ArrayAccess
     private $loggedin; // Is the used logged in ? (used to filter private links)
 
     // Constructor:
-    function __construct($isLoggedIn)
+    public function __construct($isLoggedIn)
     // Input : $isLoggedIn : is the used logged in ?
     {
         $this->loggedin = $isLoggedIn;
@@ -771,44 +891,80 @@ class linkdb implements Iterator, Countable, ArrayAccess
     }
 
     // ---- Countable interface implementation
-    public function count() { return count($this->links); }
+    public function count()
+    {
+        return count($this->links);
+    }
 
     // ---- ArrayAccess interface implementation
     public function offsetSet($offset, $value)
     {
-        if (!$this->loggedin) die('You are not authorized to add a link.');
-        if (empty($value['linkdate']) || empty($value['url'])) die('Internal Error: A link should always have a linkdate and url.');
-        if (empty($offset)) die('You must specify a key.');
+        if (!$this->loggedin) {
+            die('You are not authorized to add a link.');
+        }
+        if (empty($value['linkdate']) || empty($value['url'])) {
+            die('Internal Error: A link should always have a linkdate and url.');
+        }
+        if (empty($offset)) {
+            die('You must specify a key.');
+        }
         $this->links[$offset] = $value;
-        $this->urls[$value['url']]=$offset;
+        $this->urls[$value['url']] = $offset;
+    }
+    public function offsetExists($offset)
+    {
+        return array_key_exists($offset, $this->links);
     }
-    public function offsetExists($offset) { return array_key_exists($offset,$this->links); }
     public function offsetUnset($offset)
     {
-        if (!$this->loggedin) die('You are not authorized to delete a link.');
-        $url = $this->links[$offset]['url']; unset($this->urls[$url]);
+        if (!$this->loggedin) {
+            die('You are not authorized to delete a link.');
+        }
+        $url = $this->links[$offset]['url'];
+        unset($this->urls[$url]);
         unset($this->links[$offset]);
     }
-    public function offsetGet($offset) { return isset($this->links[$offset]) ? $this->links[$offset] : null; }
+    public function offsetGet($offset)
+    {
+        return isset($this->links[$offset]) ? $this->links[$offset] : null;
+    }
 
     // ---- Iterator interface implementation
-    function rewind() { $this->keys=array_keys($this->links); rsort($this->keys); $this->position=0; } // Start over for iteration, ordered by date (latest first).
-    function key() { return $this->keys[$this->position]; } // current key
-    function current() { return $this->links[$this->keys[$this->position]]; } // current value
-    function next() { ++$this->position; } // go to next item
-    function valid() { return isset($this->keys[$this->position]); }    // Check if current position is valid.
+    public function rewind()
+    {
+        $this->keys = array_keys($this->links);
+        rsort($this->keys);
+        $this->position = 0;
+    } // Start over for iteration, ordered by date (latest first).
+    public function key()
+    {
+        return $this->keys[$this->position];
+    } // current key
+    public function current()
+    {
+        return $this->links[$this->keys[$this->position]];
+    } // current value
+    public function next()
+    {
+        ++$this->position;
+    } // go to next item
+    public function valid()
+    {
+        return isset($this->keys[$this->position]);
+    }    // Check if current position is valid.
 
     // ---- Misc methods
     private function checkdb() // Check if db directory and file exists.
     {
-        if (!file_exists($GLOBALS['config']['DATASTORE'])) // Create a dummy database for example.
-        {
+        if (!file_exists($GLOBALS['config']['DATASTORE'])) {
+            // Create a dummy database for example.
+
              $this->links = array();
-             $link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','private'=>0,'linkdate'=>'20110914_190000','tags'=>'opensource software');
-             $this->links[$link['linkdate']] = $link;
-             $link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=','description'=>'SShhhh!!  I\'m a private link only YOU can see. You can delete me too.','private'=>1,'linkdate'=>'20110914_074522','tags'=>'secretstuff');
-             $this->links[$link['linkdate']] = $link;
-             file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk
+            $link = array('title' => 'Shaarli - sebsauvage.net', 'url' => 'http://sebsauvage.net/wiki/doku.php?id=php:shaarli', 'description' => 'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.', 'private' => 0, 'linkdate' => '20110914_190000', 'tags' => 'opensource software');
+            $this->links[$link['linkdate']] = $link;
+            $link = array('title' => 'My secret stuff... - Pastebin.com', 'url' => 'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=', 'description' => 'SShhhh!!  I\'m a private link only YOU can see. You can delete me too.', 'private' => 1, 'linkdate' => '20110914_074522', 'tags' => 'secretstuff');
+            $this->links[$link['linkdate']] = $link;
+            file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk
         }
     }
 
@@ -816,26 +972,35 @@ class linkdb implements Iterator, Countable, ArrayAccess
     private function readdb()
     {
         // Read data
-        $this->links=(file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() );
+        $this->links = (file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']), strlen(PHPPREFIX), -strlen(PHPSUFFIX))))) : array());
         // Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439
 
         // If user is not logged in, filter private links.
-        if (!$this->loggedin)
-        {
-            $toremove=array();
-            foreach($this->links as $link) { if ($link['private']!=0) $toremove[]=$link['linkdate']; }
-            foreach($toremove as $linkdate) { unset($this->links[$linkdate]); }
+        if (!$this->loggedin) {
+            $toremove = array();
+            foreach ($this->links as $link) {
+                if ($link['private'] != 0) {
+                    $toremove[] = $link['linkdate'];
+                }
+            }
+            foreach ($toremove as $linkdate) {
+                unset($this->links[$linkdate]);
+            }
         }
 
         // Keep the list of the mapping URLs-->linkdate up-to-date.
-        $this->urls=array();
-        foreach($this->links as $link) { $this->urls[$link['url']]=$link['linkdate']; }
+        $this->urls = array();
+        foreach ($this->links as $link) {
+            $this->urls[$link['url']] = $link['linkdate'];
+        }
     }
 
     // Save database from memory to disk.
     public function savedb()
     {
-        if (!$this->loggedin) die('You are not authorized to change the database.');
+        if (!$this->loggedin) {
+            die('You are not authorized to change the database.');
+        }
         file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX);
         invalidateCaches();
     }
@@ -843,7 +1008,10 @@ class linkdb implements Iterator, Countable, ArrayAccess
     // Returns the link for a given URL (if it exists). false it does not exist.
     public function getLinkFromUrl($url)
     {
-        if (isset($this->urls[$url])) return $this->links[$this->urls[$url]];
+        if (isset($this->urls[$url])) {
+            return $this->links[$this->urls[$url]];
+        }
+
         return false;
     }
 
@@ -853,36 +1021,39 @@ class linkdb implements Iterator, Countable, ArrayAccess
     {
         // FIXME: explode(' ',$searchterms) and perform a AND search.
         // FIXME: accept double-quotes to search for a string "as is" ?
-        $filtered=array();
+        $filtered = array();
         $s = strtolower($searchterms);
-        foreach($this->links as $l)
-        {
-            $found=   (strpos(strtolower($l['title']),$s)!==false)
-                   || (strpos(strtolower($l['description']),$s)!==false)
-                   || (strpos(strtolower($l['url']),$s)!==false)
-                   || (strpos(strtolower($l['tags']),$s)!==false)
-                   || (!empty($l['via']) && (strpos(strtolower($l['via']),$s)!==false));
-            if ($found) $filtered[$l['linkdate']] = $l;
+        foreach ($this->links as $l) {
+            $found = (strpos(strtolower($l['title']), $s) !== false)
+                   || (strpos(strtolower($l['description']), $s) !== false)
+                   || (strpos(strtolower($l['url']), $s) !== false)
+                   || (strpos(strtolower($l['tags']), $s) !== false)
+                   || (!empty($l['via']) && (strpos(strtolower($l['via']), $s) !== false));
+            if ($found) {
+                $filtered[$l['linkdate']] = $l;
+            }
         }
         krsort($filtered);
+
         return $filtered;
     }
 
     // Filter by tag.
     // You can specify one or more tags (tags can be separated by space or comma).
     // eg. print_r($mydb->filterTags('linux programming'));
-    public function filterTags($tags,$casesensitive=false)
+    public function filterTags($tags, $casesensitive = false)
     {
-        $t = str_replace(',',' ',($casesensitive?$tags:strtolower($tags)));
-        $searchtags=explode(' ',$t);
-        $filtered=array();
-        foreach($this->links as $l)
-        {
-            $linktags = explode(' ',($casesensitive?$l['tags']:strtolower($l['tags'])));
-            if (count(array_intersect($linktags,$searchtags)) == count($searchtags))
+        $t = str_replace(',', ' ', ($casesensitive ? $tags : strtolower($tags)));
+        $searchtags = explode(' ', $t);
+        $filtered = array();
+        foreach ($this->links as $l) {
+            $linktags = explode(' ', ($casesensitive ? $l['tags'] : strtolower($l['tags'])));
+            if (count(array_intersect($linktags, $searchtags)) == count($searchtags)) {
                 $filtered[$l['linkdate']] = $l;
+            }
         }
         krsort($filtered);
+
         return $filtered;
     }
 
@@ -891,27 +1062,31 @@ class linkdb implements Iterator, Countable, ArrayAccess
     // eg. print_r($mydb->filterDay('20120125'));
     public function filterDay($day)
     {
-        $filtered=array();
-        foreach($this->links as $l)
-        {
-            if (startsWith($l['linkdate'],$day)) $filtered[$l['linkdate']] = $l;
+        $filtered = array();
+        foreach ($this->links as $l) {
+            if (startsWith($l['linkdate'], $day)) {
+                $filtered[$l['linkdate']] = $l;
+            }
         }
         ksort($filtered);
+
         return $filtered;
     }
     // Filter by smallHash.
     // Only 1 article is returned.
     public function filterSmallHash($smallHash)
     {
-        $filtered=array();
-        foreach($this->links as $l)
-        {
-            if ($smallHash==smallHash($l['linkdate'])) // Yes, this is ugly and slow
-            {
+        $filtered = array();
+        foreach ($this->links as $l) {
+            if ($smallHash == smallHash($l['linkdate'])) {
+                // Yes, this is ugly and slow
+
                 $filtered[$l['linkdate']] = $l;
+
                 return $filtered;
             }
         }
+
         return $filtered;
     }
 
@@ -919,10 +1094,14 @@ class linkdb implements Iterator, Countable, ArrayAccess
     // Output: associative array key=tags, value=0
     public function allTags()
     {
-        $tags=array();
-        foreach($this->links as $link)
-            foreach(explode(' ',$link['tags']) as $tag)
-                if (!empty($tag)) $tags[$tag]=(empty($tags[$tag]) ? 1 : $tags[$tag]+1);
+        $tags = array();
+        foreach ($this->links as $link) {
+            foreach (explode(' ', $link['tags']) as $tag) {
+                if (!empty($tag)) {
+                    $tags[$tag] = (empty($tags[$tag]) ? 1 : $tags[$tag] + 1);
+                }
+            }
+        }
         arsort($tags); // Sort tags by usage (most used tag first)
         return $tags;
     }
@@ -931,13 +1110,13 @@ class linkdb implements Iterator, Countable, ArrayAccess
     // Output: An array containing days (in format YYYYMMDD).
     public function days()
     {
-        $linkdays=array();
-        foreach(array_keys($this->links) as $day)
-        {
-            $linkdays[substr($day,0,8)]=0;
+        $linkdays = array();
+        foreach (array_keys($this->links) as $day) {
+            $linkdays[substr($day, 0, 8)] = 0;
         }
-        $linkdays=array_keys($linkdays);
+        $linkdays = array_keys($linkdays);
         sort($linkdays);
+
         return $linkdays;
     }
 }
@@ -953,75 +1132,95 @@ function showRSS()
     $usepermalinks = isset($_GET['permalinks']);
 
     // Cache system
-    $query = $_SERVER["QUERY_STRING"];
-    $cache = new pageCache(pageUrl(),startsWith($query,'do=rss') && !isLoggedIn());
-    $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
-
-    // If cached was not found (or not usable), then read the database and build the response:
-    $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
-
-    // Optionnaly filter the results:
-    $linksToDisplay=array();
-    if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
-    elseif (!empty($_GET['searchtags']))   $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
-    else $linksToDisplay = $LINKSDB;
-    $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.
-    {
-        $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
+    $query = $_SERVER['QUERY_STRING'];
+    $cache = new pageCache(pageUrl(), startsWith($query, 'do=rss') && !isLoggedIn());
+    $cached = $cache->cachedVersion();
+    if (!empty($cached)) {
+        echo $cached;
+        exit;
     }
 
-    $pageaddr=htmlspecialchars(indexUrl());
+    // If cached was not found (or not usable), then read the database and build the response:
+    $LINKSDB = new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
+
+    // Optionnaly filter the results:
+    $linksToDisplay = array();
+    if (!empty($_GET['searchterm'])) {
+        $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
+    } elseif (!empty($_GET['searchtags'])) {
+        $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
+    } else {
+        $linksToDisplay = $LINKSDB;
+    }
+    $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.
+
+        $nblinksToDisplay = $_GET['nb'] == 'all' ? count($linksToDisplay) : max($_GET['nb'] + 0, 1);
+    }
+
+    $pageaddr = htmlspecialchars(indexUrl());
     echo '';
     echo ''.htmlspecialchars($GLOBALS['title']).''.$pageaddr.'';
     echo 'Shared linksen-en'.$pageaddr.''."\n\n";
-    if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
-    {
+    if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) {
         echo '';
         echo '';
         echo '';
         echo '';
     }
-    $i=0;
-    $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; }  // No, I can't use array_keys().
-    while ($i<$nblinksToDisplay && $i $value) {
+        $keys[] = $key;
+    }  // No, I can't use array_keys().
+    while ($i < $nblinksToDisplay && $i < count($keys)) {
         $link = $linksToDisplay[$keys[$i]];
         $guid = $pageaddr.'?'.smallHash($link['linkdate']);
         $rfc822date = linkdate2rfc822($link['linkdate']);
         $absurl = htmlspecialchars($link['url']);
-        if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl;  // make permalink URL absolute
-        if ($usepermalinks===true)
+        if (startsWith($absurl, '?')) {
+            $absurl = $pageaddr.$absurl;
+        }  // make permalink URL absolute
+        if ($usepermalinks === true) {
             echo ''.htmlspecialchars($link['title']).''.$guid.''.$guid.'';
-        else
+        } else {
             echo ''.htmlspecialchars($link['title']).''.$guid.''.$absurl.'';
-        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo ''.htmlspecialchars($rfc822date)."\n";
-        if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification)
-        {
-            foreach(explode(' ',$link['tags']) as $tag) { echo ''.htmlspecialchars($tag).''."\n"; }
+        }
+        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) {
+            echo ''.htmlspecialchars($rfc822date)."\n";
+        }
+        if ($link['tags'] != '') {
+            // Adding tags to each RSS entry (as mentioned in RSS specification)
+
+            foreach (explode(' ', $link['tags']) as $tag) {
+                echo ''.htmlspecialchars($tag).''."\n";
+            }
         }
 
         // Add permalink in description
         $descriptionlink = '(Permalink)';
         // If user wants permalinks first, put the final link in description
-        if ($usepermalinks===true) $descriptionlink = '(Link)';
-        if (strlen($link['description'])>0){
-          $descriptionlink = $descriptionlink;
+        if ($usepermalinks === true) {
+            $descriptionlink = '(Link)';
         }
-        if(!empty($link['via'])){
-          $via = 'Origin => '.htmlspecialchars(getJustDomain($link['via'])).'
'; + if (strlen($link['description']) > 0) { + $descriptionlink = $descriptionlink; + } + if (!empty($link['via'])) { + $via = 'Origin => '.htmlspecialchars(getJustDomain($link['via'])).'
'; } else { - $via = ''; + $via = ''; } - if($GLOBALS['config']['ENABLE_MARKDOWN'] === TRUE){ - $Parsedown = new Parsedown(); - echo 'setMarkupEscaped(true)->setBreaksEnabled(true)->text($link['description']).$via.$descriptionlink.']]> + if ($GLOBALS['config']['ENABLE_MARKDOWN'] === true) { + $Parsedown = new Parsedown(); + echo 'setMarkupEscaped(true)->setBreaksEnabled(true)->text($link['description']).$via.$descriptionlink.']]> '."\n
\n"; } else { - echo ' + echo ' '."\n
\n"; } - $i++; + ++$i; } echo '
'; @@ -1041,85 +1240,105 @@ function showATOM() $usepermalinks = isset($_GET['permalinks']); // Cache system - $query = $_SERVER["QUERY_STRING"]; - $cache = new pageCache(pageUrl(),startsWith($query,'do=atom') && !isLoggedIn()); - $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } + $query = $_SERVER['QUERY_STRING']; + $cache = new pageCache(pageUrl(), startsWith($query, 'do=atom') && !isLoggedIn()); + $cached = $cache->cachedVersion(); + if (!empty($cached)) { + echo $cached; + exit; + } // If cached was not found (or not usable), then read the database and build the response: - $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). - + $LINKSDB = new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). // Optionnaly filter the results: - $linksToDisplay=array(); - if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); - elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); - else $linksToDisplay = $LINKSDB; + $linksToDisplay = array(); + if (!empty($_GET['searchterm'])) { + $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); + } elseif (!empty($_GET['searchtags'])) { + $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); + } else { + $linksToDisplay = $LINKSDB; + } $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. - { - $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; + 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); } - $pageaddr=htmlspecialchars(indexUrl()); + $pageaddr = htmlspecialchars(indexUrl()); $latestDate = ''; - $entries=''; - $i=0; - $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // No, I can't use array_keys(). - while ($i<$nblinksToDisplay && $i $value) { + $keys[] = $key; + } // No, I can't use array_keys(). + while ($i < $nblinksToDisplay && $i < count($keys)) { $link = $linksToDisplay[$keys[$i]]; $guid = $pageaddr.'?'.smallHash($link['linkdate']); $iso8601date = linkdate2iso8601($link['linkdate']); - $latestDate = max($latestDate,$iso8601date); + $latestDate = max($latestDate, $iso8601date); $absurl = htmlspecialchars($link['url']); - if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute - $entries.=''.htmlspecialchars($link['title']).''; - if ($usepermalinks===true) - $entries.=''.$guid.''; - else - $entries.=''.$guid.''; + if (startsWith($absurl, '?')) { + $absurl = $pageaddr.$absurl; + } // make permalink URL absolute + $entries .= ''.htmlspecialchars($link['title']).''; + if ($usepermalinks === true) { + $entries .= ''.$guid.''; + } else { + $entries .= ''.$guid.''; + } if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) { - $entries.=''.htmlspecialchars($iso8601date).''; + $entries .= ''.htmlspecialchars($iso8601date).''; } // Add permalink in description $descriptionlink = htmlspecialchars('(Permalink)'); - if(isset($link['via']) && !empty($link['via'])){ - $via = htmlspecialchars('Origin => '.getJustDomain($link['via']).'
'); + if (isset($link['via']) && !empty($link['via'])) { + $via = htmlspecialchars('Origin => '.getJustDomain($link['via']).'
'); } else { - $via = ''; + $via = ''; } // If user wants permalinks first, put the final link in description - if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(Link)'); - if (strlen($link['description'])>0) $descriptionlink = $descriptionlink; - if($GLOBALS['config']['ENABLE_MARKDOWN'] === TRUE){ - $Parsedown = new Parsedown(); - $entries.=''.htmlspecialchars($Parsedown->setMarkupEscaped(true)->setBreaksEnabled(true)->text($link['description'])).' '.$via.$descriptionlink."\n"; + if ($usepermalinks === true) { + $descriptionlink = htmlspecialchars('(Link)'); + } + if (strlen($link['description']) > 0) { + $descriptionlink = $descriptionlink; + } + if ($GLOBALS['config']['ENABLE_MARKDOWN'] === true) { + $Parsedown = new Parsedown(); + $entries .= ''.htmlspecialchars($Parsedown->setMarkupEscaped(true)->setBreaksEnabled(true)->text($link['description'])).' '.$via.$descriptionlink."\n"; } else { - $entries.=''.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$via.$descriptionlink."\n"; + $entries .= ''.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$via.$descriptionlink."\n"; } - if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) - { - foreach(explode(' ',$link['tags']) as $tag) - { $entries.=''."\n"; } + if ($link['tags'] != '') { + // Adding tags to each ATOM entry (as mentioned in ATOM specification) + + foreach (explode(' ', $link['tags']) as $tag) { + $entries .= ''."\n"; + } } - $entries.="
\n"; - $i++; + $entries .= "
\n"; + ++$i; } - $feed=''; - $feed.=''.htmlspecialchars($GLOBALS['title']).''; - if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.=''.htmlspecialchars($latestDate).''; - $feed.=''; - if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) - { - $feed.=''; - $feed.=''; - $feed.=''; + $feed = ''; + $feed .= ''.htmlspecialchars($GLOBALS['title']).''; + if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) { + $feed .= ''.htmlspecialchars($latestDate).''; } - $feed.=''.htmlspecialchars($pageaddr).''.htmlspecialchars($pageaddr).''; - $feed.=''.htmlspecialchars($pageaddr).''."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. - $feed.=$entries; - $feed.=''; + $feed .= ''; + if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) { + $feed .= ''; + $feed .= ''; + $feed .= ''; + } + $feed .= ''.htmlspecialchars($pageaddr).''.htmlspecialchars($pageaddr).''; + $feed .= ''.htmlspecialchars($pageaddr).''."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. + $feed .= $entries; + $feed .= ''; echo $feed; $cache->cache(ob_get_contents()); @@ -1134,69 +1353,79 @@ function showATOM() function showDailyRSS() { // Cache system - $query = $_SERVER["QUERY_STRING"]; - $cache = new pageCache(pageUrl(),startsWith($query,'do=dailyrss') && !isLoggedIn()); - $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } + $query = $_SERVER['QUERY_STRING']; + $cache = new pageCache(pageUrl(), startsWith($query, 'do=dailyrss') && !isLoggedIn()); + $cached = $cache->cachedVersion(); + if (!empty($cached)) { + echo $cached; + exit; + } // If cached was not found (or not usable), then read the database and build the response: - $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). + $LINKSDB = new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). /* Some Shaarlies may have very few links, so we need to look back in time (rsort()) until we have enough days ($nb_of_days). */ - $linkdates=array(); foreach($LINKSDB as $linkdate=>$value) { $linkdates[]=$linkdate; } + $linkdates = array(); + foreach ($LINKSDB as $linkdate => $value) { + $linkdates[] = $linkdate; + } rsort($linkdates); - $nb_of_days=7; // We take 7 days. - $today=Date('Ymd'); - $days=array(); - foreach($linkdates as $linkdate) - { - $day=substr($linkdate,0,8); // Extract day (without time) - if (strcmp($day,$today)<0) - { - if (empty($days[$day])) $days[$day]=array(); - $days[$day][]=$linkdate; + $nb_of_days = 7; // We take 7 days. + $today = Date('Ymd'); + $days = array(); + foreach ($linkdates as $linkdate) { + $day = substr($linkdate, 0, 8); // Extract day (without time) + if (strcmp($day, $today) < 0) { + if (empty($days[$day])) { + $days[$day] = array(); + } + $days[$day][] = $linkdate; } - if (count($days)>$nb_of_days) break; // Have we collected enough days ? + if (count($days) > $nb_of_days) { + break; + } // Have we collected enough days ? } // Build the RSS feed. header('Content-Type: application/rss+xml; charset=utf-8'); - $pageaddr=htmlspecialchars(indexUrl()); + $pageaddr = htmlspecialchars(indexUrl()); echo ''; echo ''; echo ''; echo 'Daily - '.htmlspecialchars($GLOBALS['title']).''.$pageaddr.''; echo 'Daily shared linksen-en'.$pageaddr.''."\n"; - foreach($days as $day=>$linkdates) // For each day. - { - $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date + foreach ($days as $day => $linkdates) { + // For each day. + + $daydate = utf8_encode(strftime('%A %d, %B %Y', linkdate2timestamp($day.'_000000'))); // Full text date $rfc822date = linkdate2rfc822($day.'_000000'); - $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. + $absurl = htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. echo ''.htmlspecialchars($GLOBALS['title'].' - '.$daydate).''.$absurl.''.$absurl.''; - echo ''.htmlspecialchars($rfc822date).""; + echo ''.htmlspecialchars($rfc822date).''; // Build the HTML body of this RSS entry. - $html=''; - $href=''; - $links=array(); + $html = ''; + $href = ''; + $links = array(); // We pre-format some fields for proper output. - foreach($linkdates as $linkdate) - { + foreach ($linkdates as $linkdate) { $l = $LINKSDB[$linkdate]; - $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description'])))); + $l['formatedDescription'] = nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description'])))); $l['thumbnail'] = thumbnail($l['url']); - $l['localdate']=linkdate2locale($l['linkdate']); - if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute - $links[$linkdate]=$l; + $l['localdate'] = linkdate2locale($l['linkdate']); + if (startsWith($l['url'], '?')) { + $l['url'] = indexUrl().$l['url']; + } // make permalink URL absolute + $links[$linkdate] = $l; } // Then build the HTML for this day: - $tpl = new RainTPL; - $tpl->assign('links',$links); - $html = $tpl->draw('dailyrss',$return_string=true); + $tpl = new RainTPL(); + $tpl->assign('links', $links); + $html = $tpl->draw('dailyrss', $return_string = true); echo "\n"; echo ''."\n\n\n"; - } echo ''; @@ -1208,31 +1437,37 @@ function showDailyRSS() // "Daily" page. function showDaily() { - $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). + $LINKSDB = new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). - - $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. - if (isset($_GET['day'])) $day=$_GET['day']; - - $days = $LINKSDB->days(); - $i = array_search($day,$days); - if ($i==false) { $i=count($days)-1; $day=$days[$i]; } - $previousday=''; - $nextday=''; - if ($i!==false) - { - if ($i>1) $previousday=$days[$i-1]; - if ($ifilterDay($day); + $days = $LINKSDB->days(); + $i = array_search($day, $days); + if ($i == false) { + $i = count($days) - 1; + $day = $days[$i]; + } + $previousday = ''; + $nextday = ''; + if ($i !== false) { + if ($i > 1) { + $previousday = $days[$i - 1]; + } + if ($i < count($days) - 1) { + $nextday = $days[$i + 1]; + } + } + + $linksToDisplay = $LINKSDB->filterDay($day); // We pre-format some fields for proper output. - foreach($linksToDisplay as $key=>$link) - { - $taglist = explode(' ',$link['tags']); + foreach ($linksToDisplay as $key => $link) { + $taglist = explode(' ', $link['tags']); uasort($taglist, 'strcasecmp'); - $linksToDisplay[$key]['taglist']=$taglist; - $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); + $linksToDisplay[$key]['taglist'] = $taglist; + $linksToDisplay[$key]['formatedDescription'] = nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); } @@ -1241,57 +1476,61 @@ function showDaily() so I manually spread entries with a simple method: I roughly evaluate the height of a div according to title and description length. */ - $columns=array(array(),array(),array()); // Entries to display, for each column. - $fill=array(0,0,0); // Rough estimate of columns fill. - foreach($linksToDisplay as $key=>$link) - { + $columns = array(array(), array(), array()); // Entries to display, for each column. + $fill = array(0, 0, 0); // Rough estimate of columns fill. + foreach ($linksToDisplay as $key => $link) { // Roughly estimate length of entry (by counting characters) // Title: 30 chars = 1 line. 1 line is 30 pixels height. // Description: 836 characters gives roughly 342 pixel height. // This is not perfect, but it's usually ok. - $length=strlen($link['title'])+(342*strlen($link['description']))/836; - if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height. + $length = strlen($link['title']) + (342 * strlen($link['description'])) / 836; + if ($link['thumbnail']) { + $length += 100; + } // 1 thumbnails roughly takes 100 pixels height. // Then put in column which is the less filled: - $smallest=min($fill); // find smallest value in array. - $index=array_search($smallest,$fill); // find index of this smallest value. - array_push($columns[$index],$link); // Put entry in this column. - $fill[$index]+=$length; + $smallest = min($fill); // find smallest value in array. + $index = array_search($smallest, $fill); // find index of this smallest value. + array_push($columns[$index], $link); // Put entry in this column. + $fill[$index] += $length; } - $PAGE = new pageBuilder; - $PAGE->assign('linksToDisplay',$linksToDisplay); - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('col1',$columns[0]); - $PAGE->assign('col1',$columns[0]); - $PAGE->assign('col2',$columns[1]); - $PAGE->assign('col3',$columns[2]); - $PAGE->assign('day',utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000')))); - $PAGE->assign('previousday',$previousday); - $PAGE->assign('nextday',$nextday); + $PAGE = new pageBuilder(); + $PAGE->assign('linksToDisplay', $linksToDisplay); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('col1', $columns[0]); + $PAGE->assign('col1', $columns[0]); + $PAGE->assign('col2', $columns[1]); + $PAGE->assign('col3', $columns[2]); + $PAGE->assign('day', utf8_encode(strftime('%A %d, %B %Y', linkdate2timestamp($day.'_000000')))); + $PAGE->assign('previousday', $previousday); + $PAGE->assign('nextday', $nextday); $PAGE->renderPage('daily'); exit; } - // ------------------------------------------------------------------------------------------ // Render HTML page (according to URL parameters and user rights) function renderPage() { - $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). + $LINKSDB = new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). // -------- Display login form. - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=login')) - { - if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli - $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. - $PAGE = new pageBuilder; - $PAGE->assign('token',$token); - $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:'')); + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=login')) { + if ($GLOBALS['config']['OPEN_SHAARLI']) { + header('Location: ?'); + exit; + } // No need to login for open Shaarli + $token = ''; + if (ban_canLogin()) { + $token = getToken(); + } // Do not waste token generation if not useful. + $PAGE = new pageBuilder(); + $PAGE->assign('token', $token); + $PAGE->assign('returnurl', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); $PAGE->renderPage('loginform'); exit; } // -------- User wants to logout. - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=logout')) - { + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=logout')) { invalidateCaches(); logout(); header('Location: ?'); @@ -1299,73 +1538,80 @@ function renderPage() } // -------- Picture wall - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=picwall')) - { + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=picwall')) { // Optionnaly filter the results: - $links=array(); - if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); - elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); - else $links = $LINKSDB; - $body=''; - $linksToDisplay=array(); + $links = array(); + if (!empty($_GET['searchterm'])) { + $links = $LINKSDB->filterFulltext($_GET['searchterm']); + } elseif (!empty($_GET['searchtags'])) { + $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); + } else { + $links = $LINKSDB; + } + $body = ''; + $linksToDisplay = array(); // Get only links which have a thumbnail. - foreach($links as $link) - { - $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES); - $thumb=lazyThumbnail($link['url'],$permalink); - if ($thumb!='') // Only output links which have a thumbnail. - { - $link['thumbnail']=$thumb; // Thumbnail HTML code. - $link['permalink']=$permalink; - $linksToDisplay[]=$link; // Add to array. + foreach ($links as $link) { + $permalink = '?'.htmlspecialchars(smallhash($link['linkdate']), ENT_QUOTES); + $thumb = lazyThumbnail($link['url'], $permalink); + if ($thumb != '') { + // Only output links which have a thumbnail. + + $link['thumbnail'] = $thumb; // Thumbnail HTML code. + $link['permalink'] = $permalink; + $linksToDisplay[] = $link; // Add to array. } } - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('linksToDisplay',$linksToDisplay); + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('linksToDisplay', $linksToDisplay); $PAGE->renderPage('picwall'); exit; } // -------- Tag cloud - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tagcloud')) - { - $tags= $LINKSDB->allTags(); + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=tagcloud')) { + $tags = $LINKSDB->allTags(); // We sort tags alphabetically, then choose a font size according to count. // First, find max value. - $maxcount=0; foreach($tags as $key=>$value) $maxcount=max($maxcount,$value); + $maxcount = 0; + foreach ($tags as $key => $value) { + $maxcount = max($maxcount, $value); + } $linkCount = count($LINKSDB); ksort($tags); - $tagList=array(); - foreach($tags as $key=>$value) - // Tag font size scaling: default 15 and 30 logarithm bases affect scaling, 22 and 6 are arbitrary font sizes for max and min sizes. - { - $tagList[$key] = array('count'=>$value,'size'=>log($value, 5) / log($maxcount, 3) * (4.8-0.8) + 0.8); + $tagList = array(); + foreach ($tags as $key => $value) { + // Tag font size scaling: default 15 and 30 logarithm bases affect scaling, 22 and 6 are arbitrary font sizes for max and min sizes. + + $tagList[$key] = array('count' => $value, 'size' => log($value, 5) / log($maxcount, 3) * (4.8 - 0.8) + 0.8); } - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('tags',$tagList); + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('tags', $tagList); $PAGE->renderPage('tagcloud'); exit; } // Display openseach plugin (XML) - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=opensearch')) { + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=opensearch')) { header('Content-Type: application/xml; charset=utf-8'); - $PAGE = new pageBuilder; + $PAGE = new pageBuilder(); $PAGE->assign('serverurl', $GLOBALS['title']); - $PAGE->assign('pagetitle',$GLOBALS['title']); + $PAGE->assign('pagetitle', $GLOBALS['title']); $PAGE->renderPage('opensearch'); exit; } // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) - if (isset($_GET['addtag'])) - { + if (isset($_GET['addtag'])) { // Get previous URL (http_referer) and add the tag to the searchtags parameters in query. - if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER - parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); + if (empty($_SERVER['HTTP_REFERER'])) { + header('Location: ?searchtags='.urlencode($_GET['addtag'])); + exit; + } // In case browser does not send HTTP_REFERER + parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); $params['searchtags'] = (empty($params['searchtags']) ? trim($_GET['addtag']) : trim($params['searchtags']).' '.trim($_GET['addtag'])); unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) header('Location: ?'.http_build_query($params)); @@ -1373,16 +1619,21 @@ function renderPage() } // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) - if (isset($_GET['removetag'])) - { + if (isset($_GET['removetag'])) { // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query. - if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER - parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); - if (isset($params['searchtags'])) - { - $tags = explode(' ',$params['searchtags']); - $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. - if (count($tags)==0) unset($params['searchtags']); else $params['searchtags'] = implode(' ',$tags); + if (empty($_SERVER['HTTP_REFERER'])) { + header('Location: ?'); + exit; + } // In case browser does not send HTTP_REFERER + parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); + if (isset($params['searchtags'])) { + $tags = explode(' ', $params['searchtags']); + $tags = array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. + if (count($tags) == 0) { + unset($params['searchtags']); + } else { + $params['searchtags'] = implode(' ', $tags); + } unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) } header('Location: ?'.http_build_query($params)); @@ -1390,56 +1641,53 @@ function renderPage() } // -------- User wants to change the number of links per page (linksperpage=...) - if (isset($_GET['linksperpage'])) - { - if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); } + if (isset($_GET['linksperpage'])) { + if (is_numeric($_GET['linksperpage'])) { + $_SESSION['LINKS_PER_PAGE'] = abs(intval($_GET['linksperpage'])); + } // Make sure the referer is from Shaarli itself. $referer = '?'; - if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) + if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST), $_SERVER['HTTP_HOST']) == 0) { $referer = $_SERVER['HTTP_REFERER']; + } header('Location: '.$referer); exit; } // -------- User wants to see only private links (toggle) - if (isset($_GET['privateonly'])) - { - if (empty($_SESSION['privateonly'])) - { - $_SESSION['privateonly']=1; // See only private links - } - else - { + if (isset($_GET['privateonly'])) { + if (empty($_SESSION['privateonly'])) { + $_SESSION['privateonly'] = 1; // See only private links + } else { unset($_SESSION['privateonly']); // See all links } // Make sure the referer is from Shaarli itself. $referer = '?'; - if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) + if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST), $_SERVER['HTTP_HOST']) == 0) { $referer = $_SERVER['HTTP_REFERER']; + } header('Location: '.$referer); exit; } // -------- Handle other actions allowed for non-logged in users: - if (!isLoggedIn()) - { + if (!isLoggedIn()) { // User tries to post new link but is not loggedin: // Show login screen, then redirect to ?post=... - if (isset($_GET['post'])) - { - header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link. + if (isset($_GET['post'])) { + header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title']) ? '&title='.urlencode($_GET['title']) : '').(!empty($_GET['source']) ? '&source='.urlencode($_GET['source']) : '')); // Redirect to login page, then back to post link. exit; } - // Same case as above except that user tried to access ?do=addlink without being logged in - // Note: passing empty parameters makes Shaarli generate default URLs and descriptions. - if (isset($_GET['do']) && $_GET['do'] === 'addlink') { - header('Location: ?do=login&post='); - exit; - } + // Same case as above except that user tried to access ?do=addlink without being logged in + // Note: passing empty parameters makes Shaarli generate default URLs and descriptions. + if (isset($_GET['do']) && $_GET['do'] === 'addlink') { + header('Location: ?do=login&post='); + exit; + } - $PAGE = new pageBuilder; - buildLinkList($PAGE,$LINKSDB); // Compute list of links to display + $PAGE = new pageBuilder(); + buildLinkList($PAGE, $LINKSDB); // Compute list of links to display $PAGE->renderPage('linklist'); exit; // Never remove this one ! All operations below are reserved for logged in user. } @@ -1447,124 +1695,128 @@ function renderPage() // -------- All other functions are reserved for the registered user: // -------- Display the Tools menu if requested (import/export/bookmarklet...) - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tools')) - { - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('pageabsaddr',indexUrl()); + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=tools')) { + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('pageabsaddr', indexUrl()); $PAGE->renderPage('tools'); exit; } // -------- User wants to change his/her password. - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=changepasswd')) - { - if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.'); - if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) - { - if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=changepasswd')) { + if ($GLOBALS['config']['OPEN_SHAARLI']) { + die('You are not supposed to change a password on an Open Shaarli.'); + } + if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) { + if (!tokenOk($_POST['token'])) { + die('Wrong token.'); + } // Go away ! // Make sure old password is correct. $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']); - if ($oldhash!=$GLOBALS['hash']) { echo ''; exit; } + if ($oldhash != $GLOBALS['hash']) { + echo ''; + exit; + } // Save new password - $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. + $GLOBALS['salt'] = sha1(uniqid('', true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); writeConfig(); echo ''; exit; - } - else // show the change password form. - { - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('token',getToken()); + } else { + // show the change password form. + + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('token', getToken()); $PAGE->renderPage('changepassword'); exit; } } // -------- User wants to change configuration - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=configure')) - { - if (!empty($_POST['title']) ) - { - if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=configure')) { + if (!empty($_POST['title'])) { + if (!tokenOk($_POST['token'])) { + die('Wrong token.'); + } // Go away ! $tz = 'UTC'; - if (!empty($_POST['continent']) && !empty($_POST['city'])) - if (isTZvalid($_POST['continent'],$_POST['city'])) + if (!empty($_POST['continent']) && !empty($_POST['city'])) { + if (isTZvalid($_POST['continent'], $_POST['city'])) { $tz = $_POST['continent'].'/'.$_POST['city']; + } + } $GLOBALS['timezone'] = $tz; - $GLOBALS['title']=htmlentities(strip_tags($_POST['title'])); - $GLOBALS['titleLink']=htmlentities(strip_tags($_POST['titleLink'])); - $GLOBALS['redirector']=$_POST['redirector']; - $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']); - $GLOBALS['disablejquery']=!empty($_POST['disablejquery']); - $GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']); - $GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']); + $GLOBALS['title'] = htmlentities(strip_tags($_POST['title'])); + $GLOBALS['titleLink'] = htmlentities(strip_tags($_POST['titleLink'])); + $GLOBALS['redirector'] = $_POST['redirector']; + $GLOBALS['disablesessionprotection'] = !empty($_POST['disablesessionprotection']); + $GLOBALS['disablejquery'] = !empty($_POST['disablejquery']); + $GLOBALS['privateLinkByDefault'] = !empty($_POST['privateLinkByDefault']); + $GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = !empty($_POST['enableRssPermalinks']); $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); $GLOBALS['config']['ENABLE_MARKDOWN'] = !empty($_POST['enableMarkdown']); $GLOBALS['config']['HIDE_TIMESTAMPS'] = !empty($_POST['hideTimestamps']); - $GLOBALS['config']['BAN_AFTER'] = (int)$_POST['banAfter']; - $GLOBALS['config']['BAN_DURATION'] = (int)$_POST['banDuration']; + $GLOBALS['config']['BAN_AFTER'] = (int) $_POST['banAfter']; + $GLOBALS['config']['BAN_DURATION'] = (int) $_POST['banDuration']; $GLOBALS['config']['THEME'] = htmlentities(strip_tags($_POST['theme'])); - $GLOBALS['config']['LINKS_PER_PAGE'] = (int)$_POST['linkPerPage']; + $GLOBALS['config']['LINKS_PER_PAGE'] = (int) $_POST['linkPerPage']; $GLOBALS['config']['ENABLE_THUMBNAILS'] = !empty($_POST['enableThumbnails']); $GLOBALS['config']['ENABLE_FAVICON'] = !empty($_POST['enableFavicon']); $GLOBALS['config']['ENABLE_LOCALCACHE'] = !empty($_POST['enableCache']); $GLOBALS['config']['externalThumbshot'] = $_POST['externalThumbshot']; $GLOBALS['config']['contactLink'] = $_POST['contactLink']; - $_SESSION['LINKS_PER_PAGE'] = (int)$_POST['linkPerPage']; + $_SESSION['LINKS_PER_PAGE'] = (int) $_POST['linkPerPage']; $GLOBALS['config']['DATE_FORMAT'] = strip_tags($_POST['dateFormat']); writeConfig(); echo ''; exit; - } - else // Show the configuration form. - { - $PAGE = new pageBuilder; - $PAGE->assign('themes',getAllTheme()); - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('token',getToken()); - $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); - $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); - list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); - $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ? - $PAGE->assign('timezone_js',$timezone_js); - if($_GET['config'] === 'myshaarli'){ - raintpl::$tpl_dir = 'tpl/myShaarli/'; - $PAGE->renderPage('configure'); + } else { + // Show the configuration form. + + $PAGE = new pageBuilder(); + $PAGE->assign('themes', getAllTheme()); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('token', getToken()); + $PAGE->assign('title', htmlspecialchars(empty($GLOBALS['title']) ? '' : $GLOBALS['title'], ENT_QUOTES)); + $PAGE->assign('redirector', htmlspecialchars(empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'], ENT_QUOTES)); + list($timezone_form, $timezone_js) = templateTZform($GLOBALS['timezone']); + $PAGE->assign('timezone_form', $timezone_form); // FIXME: put entire tz form generation in template ? + $PAGE->assign('timezone_js', $timezone_js); + if ($_GET['config'] === 'myshaarli') { + raintpl::$tpl_dir = 'tpl/myShaarli/'; + $PAGE->renderPage('configure'); } else { - $PAGE->renderPage('configure'); + $PAGE->renderPage('configure'); } exit; } } // -------- User wants to rename a tag or delete it - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=changetag')) - { - if (empty($_POST['fromtag']) && empty($_POST['tagToDelete'])) - { - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('token',getToken()); + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=changetag')) { + if (empty($_POST['fromtag']) && empty($_POST['tagToDelete'])) { + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('token', getToken()); $PAGE->renderPage('changetag'); exit; } - if (!tokenOk($_POST['token'])) die('Wrong token.'); + if (!tokenOk($_POST['token'])) { + die('Wrong token.'); + } // Delete a tag: - if (!empty($_POST['deletetag']) && !empty($_POST['tagToDelete'])) - { - $needle=trim($_POST['tagToDelete']); - $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. - foreach($linksToAlter as $key=>$value) - { - $tags = explode(' ',trim($value['tags'])); - unset($tags[array_search($needle,$tags)]); // Remove tag. - $value['tags']=trim(implode(' ',$tags)); - $LINKSDB[$key]=$value; + if (!empty($_POST['deletetag']) && !empty($_POST['tagToDelete'])) { + $needle = trim($_POST['tagToDelete']); + $linksToAlter = $LINKSDB->filterTags($needle, true); // true for case-sensitive tag search. + foreach ($linksToAlter as $key => $value) { + $tags = explode(' ', trim($value['tags'])); + unset($tags[array_search($needle, $tags)]); // Remove tag. + $value['tags'] = trim(implode(' ', $tags)); + $LINKSDB[$key] = $value; } $LINKSDB->savedb(); // save to disk echo ''; @@ -1572,16 +1824,14 @@ function renderPage() } // Rename a tag: - if (!empty($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) - { - $needle=trim($_POST['fromtag']); - $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. - foreach($linksToAlter as $key=>$value) - { - $tags = explode(' ',trim($value['tags'])); - $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Remplace tags value. - $value['tags']=trim(implode(' ',$tags)); - $LINKSDB[$key]=$value; + if (!empty($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { + $needle = trim($_POST['fromtag']); + $linksToAlter = $LINKSDB->filterTags($needle, true); // true for case-sensitive tag search. + foreach ($linksToAlter as $key => $value) { + $tags = explode(' ', trim($value['tags'])); + $tags[array_search($needle, $tags)] = trim($_POST['totag']); // Remplace tags value. + $value['tags'] = trim(implode(' ', $tags)); + $LINKSDB[$key] = $value; } $LINKSDB->savedb(); // save to disk echo ''; @@ -1590,170 +1840,193 @@ function renderPage() } // -------- User wants to add a link without using the bookmarklet: show form. - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink')) - { - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=addlink')) { + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); $PAGE->renderPage('addlink'); exit; } // -------- User clicked the "Save" button when editing a link: Save link to database. - if (isset($_POST['save_edit'])) - { - if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! - $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. - $linkdate=$_POST['lf_linkdate']; + if (isset($_POST['save_edit'])) { + if (!tokenOk($_POST['token'])) { + die('Wrong token.'); + } // Go away ! + $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); // Remove multiple spaces. + $linkdate = $_POST['lf_linkdate']; $url = trim($_POST['lf_url']); - if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?') && !startsWith($url,'javascript:')) + if (!startsWith($url, 'http:') && !startsWith($url, 'https:') && !startsWith($url, 'ftp:') && !startsWith($url, 'magnet:') && !startsWith($url, '?') && !startsWith($url, 'javascript:')) { $url = 'http://'.$url; - $link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0), - 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags), 'via'=>trim($_POST['lf_via'])); - if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. + } + $link = array('title' => trim($_POST['lf_title']), 'url' => $url, 'description' => trim($_POST['lf_description']), 'private' => (isset($_POST['lf_private']) ? 1 : 0), + 'linkdate' => $linkdate, 'tags' => str_replace(',', ' ', $tags), 'via' => trim($_POST['lf_via']), ); + if ($link['title'] == '') { + $link['title'] = $link['url']; + } // If title is empty, use the URL as title. $LINKSDB[$linkdate] = $link; $LINKSDB->savedb(); // save to disk pubsubhub(); // If we are called from the bookmarklet, we must close the popup: - if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; exit; } - $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); + if (isset($_GET['source']) && ($_GET['source'] == 'bookmarklet' || $_GET['source'] == 'firefoxsocialapi')) { + echo ''; + exit; + } + $returnurl = (isset($_POST['returnurl']) ? $_POST['returnurl'] : '?'); $returnurl .= '#'.smallHash($linkdate); // Scroll to the link which has been edited. - if (strstr($returnurl, "do=addlink")) { $returnurl = '?'; } //if we come from ?do=addlink, set returnurl to homepage instead + if (strstr($returnurl, 'do=addlink')) { + $returnurl = '?'; + } //if we come from ?do=addlink, set returnurl to homepage instead header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on. exit; } // -------- User clicked the "Cancel" button when editing a link. - if (isset($_POST['cancel_edit'])) - { + if (isset($_POST['cancel_edit'])) { // If we are called from the bookmarklet, we must close the popup; - if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; exit; } - $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); + if (isset($_GET['source']) && ($_GET['source'] == 'bookmarklet' || $_GET['source'] == 'firefoxsocialapi')) { + echo ''; + exit; + } + $returnurl = (isset($_POST['returnurl']) ? $_POST['returnurl'] : '?'); $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. exit; } // -------- User clicked the "Delete" button when editing a link : Delete link from database. - if (isset($_POST['delete_link'])) - { - if (!tokenOk($_POST['token'])) die('Wrong token.'); + if (isset($_POST['delete_link'])) { + if (!tokenOk($_POST['token'])) { + die('Wrong token.'); + } // We do not need to ask for confirmation: // - confirmation is handled by javascript // - we are protected from XSRF by the token. - $linkdate=$_POST['lf_linkdate']; + $linkdate = $_POST['lf_linkdate']; unset($LINKSDB[$linkdate]); $LINKSDB->savedb(); // save to disk // If we are called from the bookmarklet, we must close the popup: - if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; } + if (isset($_GET['source']) && $_GET['source'] == 'bookmarklet') { + echo ''; + exit; + } header('Location: ?'); // After deleting the link, redirect to the home page. exit; } // -------- User clicked the "EDIT" button on a link: Display link edit form. - if (isset($_GET['edit_link'])) - { + if (isset($_GET['edit_link'])) { $link = $LINKSDB[$_GET['edit_link']]; // Read database - if (!$link) { header('Location: ?'); exit; } // Link not found in database. - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('link',$link); - $PAGE->assign('link_is_new',false); - $PAGE->assign('token',getToken()); // XSRF protection. - $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); + if (!$link) { + header('Location: ?'); + exit; + } // Link not found in database. + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('link', $link); + $PAGE->assign('link_is_new', false); + $PAGE->assign('token', getToken()); // XSRF protection. + $PAGE->assign('http_referer', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); $PAGE->renderPage('editlink'); exit; } // -------- User want to post a new link: Display link edit form. - if (isset($_GET['post'])) - { - $url=$_GET['post']; + if (isset($_GET['post'])) { + $url = $_GET['post']; // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...) - $i=stripos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i); - $i=stripos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i); - $i=stripos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i); + $i = stripos($url, '&utm_source='); + if ($i !== false) { + $url = substr($url, 0, $i); + } + $i = stripos($url, '?utm_source='); + if ($i !== false) { + $url = substr($url, 0, $i); + } + $i = stripos($url, '#xtor=RSS-'); + if ($i !== false) { + $url = substr($url, 0, $i); + } $link_is_new = false; $link = $LINKSDB->getLinkFromUrl($url); // Check if URL is not already in database (in this case, we will edit the existing link) - if (!$link) - { + if (!$link) { $link_is_new = true; // This is a new link $linkdate = strval(date('Ymd_His')); // Get title if it was provided in URL (by the bookmarklet). $title = empty($_GET['title']) ? '' : htmlspecialchars($_GET['title']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] $description = (empty($_GET['description']) ? '' : htmlspecialchars($_GET['description'])); - $tags = (empty($_GET['tags']) ? '' : htmlspecialchars($_GET['tags'] )); - $via = (empty($_GET['via']) ? '' : htmlspecialchars($_GET['via'] )); - $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); - 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 (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http') - { - list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive. - // FIXME: Decode charset according to specified in either 1) HTTP response headers or 2) in html - if (strpos($status,'200 OK')!==false) - { - // Look for charset in html header. - preg_match('##Usi', $data, $meta); - - // If found, extract encoding. - if (!empty($meta[0])) - { - // Get encoding specified in header. - preg_match('#charset="?(.*)"#si', $meta[0], $enc); - // If charset not found, use utf-8. - $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8'; - } - else { $html_charset = 'utf-8'; } - - // Extract title - $title = html_extract_title($data); - if (!empty($title)) - { - // Re-encode title in utf-8 if necessary. - $title = ($html_charset == 'iso-8859-1') ? utf8_encode($title) : $title; - } - } + $tags = (empty($_GET['tags']) ? '' : htmlspecialchars($_GET['tags'])); + $via = (empty($_GET['via']) ? '' : htmlspecialchars($_GET['via'])); + $private = (!empty($_GET['private']) && $_GET['private'] === '1' ? 1 : 0); + if (($url != '') && parse_url($url, PHP_URL_SCHEME) == '') { + $url = 'http://'.$url; } - if ($url=='') // In case of empty URL, this is just a text (with a link that points to itself) - { - $url='?'.smallHash($linkdate); - $title='Note: '; + // 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') { + list($status, $headers, $data) = getHTTP($url, 4); // Short timeout to keep the application responsive. + // FIXME: Decode charset according to specified in either 1) HTTP response headers or 2) in html + if (strpos($status, '200 OK') !== false) { + // Look for charset in html header. + preg_match('##Usi', $data, $meta); + + // If found, extract encoding. + if (!empty($meta[0])) { + // Get encoding specified in header. + preg_match('#charset="?(.*)"#si', $meta[0], $enc); + // If charset not found, use utf-8. + $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8'; + } else { + $html_charset = 'utf-8'; + } + + // Extract title + $title = html_extract_title($data); + if (!empty($title)) { + // Re-encode title in utf-8 if necessary. + $title = ($html_charset == 'iso-8859-1') ? utf8_encode($title) : $title; + } + } + } + if ($url == '') { + // In case of empty URL, this is just a text (with a link that points to itself) + + $url = '?'.smallHash($linkdate); + $title = 'Note: '; $tags .= 'note '; } - $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'via' => $via,'private'=>$private); + $link = array('linkdate' => $linkdate, 'title' => $title, 'url' => $url, 'description' => $description, 'tags' => $tags, 'via' => $via, 'private' => $private); } - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('link',$link); - $PAGE->assign('link_is_new',$link_is_new); - $PAGE->assign('token',getToken()); // XSRF protection. - $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('link', $link); + $PAGE->assign('link_is_new', $link_is_new); + $PAGE->assign('token', getToken()); // XSRF protection. + $PAGE->assign('http_referer', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); $PAGE->renderPage('editlink'); exit; } // -------- Export as Netscape Bookmarks HTML file. - if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=export')) - { - if (empty($_GET['what'])) - { - $PAGE = new pageBuilder; - $PAGE->assign('linkcount',count($LINKSDB)); + if (isset($_SERVER['QUERY_STRING']) && startswith($_SERVER['QUERY_STRING'], 'do=export')) { + if (empty($_GET['what'])) { + $PAGE = new pageBuilder(); + $PAGE->assign('linkcount', count($LINKSDB)); $PAGE->renderPage('export'); exit; } - $exportWhat=$_GET['what']; - if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???'); + $exportWhat = $_GET['what']; + if (!array_intersect(array('all', 'public', 'private'), array($exportWhat))) { + die('What are you trying to export ???'); + } header('Content-Type: text/html; charset=utf-8'); header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html'); - $currentdate=date('Y/m/d H:i:s'); + $currentdate = date('Y/m/d H:i:s'); echo << http://img.youtube.com/vi/spVypYk4kto/default.jpg ) // ^^^^^^^^^^^ ^^^^^^^^^^^ - $domain = parse_url($url,PHP_URL_HOST); - if ($domain=='youtube.com' || $domain=='www.youtube.com') - { - parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail - if (!empty($params['v'])) return array('src'=>'https://img.youtube.com/vi/'.$params['v'].'/default.jpg', - 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail'); + $domain = parse_url($url, PHP_URL_HOST); + if ($domain == 'youtube.com' || $domain == 'www.youtube.com') { + parse_str(parse_url($url, PHP_URL_QUERY), $params); // Extract video ID and get thumbnail + if (!empty($params['v'])) { + return array('src' => 'https://img.youtube.com/vi/'.$params['v'].'/default.jpg', + 'href' => $href, 'width' => '120', 'height' => '90', 'alt' => 'YouTube thumbnail', ); + } } - if ($domain=='youtu.be') // Youtube short links - { - $path = parse_url($url,PHP_URL_PATH); - return array('src'=>'https://img.youtube.com/vi'.$path.'/default.jpg', - 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail'); + if ($domain == 'youtu.be') { + // Youtube short links + + $path = parse_url($url, PHP_URL_PATH); + + return array('src' => 'https://img.youtube.com/vi'.$path.'/default.jpg', + 'href' => $href, 'width' => '120', 'height' => '90', 'alt' => 'YouTube thumbnail', ); } - if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting - { - parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename. - if (!empty($params) && !empty($params['img'])) return array('src'=>'http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']), - 'href'=>$href,'style'=>'max-width:120px; max-height:150px','alt'=>'pix.toile-libre.org thumbnail'); + if ($domain == 'pix.toile-libre.org') { + // pix.toile-libre.org image hosting + + parse_str(parse_url($url, PHP_URL_QUERY), $params); // Extract image filename. + if (!empty($params) && !empty($params['img'])) { + return array('src' => 'http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']), + 'href' => $href, 'style' => 'max-width:120px; max-height:150px', 'alt' => 'pix.toile-libre.org thumbnail', ); + } } - if ($domain=='imgur.com') - { - $path = parse_url($url,PHP_URL_PATH); - if (startsWith($path,'/a/') && empty($GLOBALS['config']['externalThumbshot'])){ - return array(); // Thumbnails for albums are not available. + if ($domain == 'imgur.com') { + $path = parse_url($url, PHP_URL_PATH); + if (startsWith($path, '/a/') && empty($GLOBALS['config']['externalThumbshot'])) { + return array(); // Thumbnails for albums are not available. + } + if (startsWith($path, '/r/')) { + return array('src' => 'https://i.imgur.com/'.basename($path).'s.jpg', + 'href' => $href, 'width' => '90', 'height' => '90', 'alt' => 'imgur.com thumbnail', ); + } + if (startsWith($path, '/gallery/')) { + return array('src' => 'https://i.imgur.com'.substr($path, 8).'s.jpg', + 'href' => $href, 'width' => '90', 'height' => '90', 'alt' => 'imgur.com thumbnail', ); } - if (startsWith($path,'/r/')) return array('src'=>'https://i.imgur.com/'.basename($path).'s.jpg', - 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); - if (startsWith($path,'/gallery/')) return array('src'=>'https://i.imgur.com'.substr($path,8).'s.jpg', - 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); - if (substr_count($path,'/')==1) return array('src'=>'https://i.imgur.com/'.substr($path,1).'s.jpg', - 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); - } - if ($domain=='i.imgur.com') - { - $pi = pathinfo(parse_url($url,PHP_URL_PATH)); - if (!empty($pi['filename'])) return array('src'=>'https://i.imgur.com/'.$pi['filename'].'s.jpg', - 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); - } - if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com') - { - if (strpos($url,'dailymotion.com/video/')!==false) - { - $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url); - return array('src'=>$thumburl, - 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'DailyMotion thumbnail'); + if (substr_count($path, '/') == 1) { + return array('src' => 'https://i.imgur.com/'.substr($path, 1).'s.jpg', + 'href' => $href, 'width' => '90', 'height' => '90', 'alt' => 'imgur.com thumbnail', ); } } - if (endsWith($domain,'.imageshack.us')) - { - $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); - if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') - { - $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext; - return array('src'=>$thumburl, - 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'imageshack.us thumbnail'); + if ($domain == 'i.imgur.com') { + $pi = pathinfo(parse_url($url, PHP_URL_PATH)); + if (!empty($pi['filename'])) { + return array('src' => 'https://i.imgur.com/'.$pi['filename'].'s.jpg', + 'href' => $href, 'width' => '90', 'height' => '90', 'alt' => 'imgur.com thumbnail', ); } } - if(!empty($GLOBALS['config']['externalThumbshot']) && $GLOBALS['config']['ENABLE_THUMBNAILS'] !== false) - { - if(strlen($url) <= 7){ - $url = serverUrl().'/'.$url; + if ($domain == 'dailymotion.com' || $domain == 'www.dailymotion.com') { + if (strpos($url, 'dailymotion.com/video/') !== false) { + $thumburl = str_replace('dailymotion.com/video/', 'dailymotion.com/thumbnail/video/', $url); + + return array('src' => $thumburl, + 'href' => $href, 'width' => '120', 'style' => 'height:auto;', 'alt' => 'DailyMotion thumbnail', ); } - $thumburl = $GLOBALS['config']['externalThumbshot'].urlencode($url); - return array('src'=>$thumburl,'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'Custom Thumbshot'); + } + if (endsWith($domain, '.imageshack.us')) { + $ext = strtolower(pathinfo($url, PATHINFO_EXTENSION)); + if ($ext == 'jpg' || $ext == 'jpeg' || $ext == 'png' || $ext == 'gif') { + $thumburl = substr($url, 0, strlen($url) - strlen($ext)).'th.'.$ext; + + return array('src' => $thumburl, + 'href' => $href, 'width' => '120', 'style' => 'height:auto;', 'alt' => 'imageshack.us thumbnail', ); + } + } + if (!empty($GLOBALS['config']['externalThumbshot']) && $GLOBALS['config']['ENABLE_THUMBNAILS'] !== false) { + if (strlen($url) <= 7) { + $url = serverUrl().'/'.$url; + } + $thumburl = $GLOBALS['config']['externalThumbshot'].urlencode($url); + + return array('src' => $thumburl, 'href' => $href, 'width' => '120', 'style' => 'height:auto;', 'alt' => 'Custom Thumbshot'); } // Some other hosts are SLOW AS HELL and usually require an extra HTTP request to get the thumbnail URL. // So we deport the thumbnail generation in order not to slow down page generation // (and we also cache the thumbnail) - if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache. + if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) { + return array(); + } // If local cache is disabled, no thumbnails for services which require the use a local cache. - if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') - || $domain=='vimeo.com' - || $domain=='ted.com' || endsWith($domain,'.ted.com') - || $domain=='xkcd.com' || endsWith($domain,'.xkcd.com') - ) - { - if ($domain=='vimeo.com') - { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric) - $path = parse_url($url,PHP_URL_PATH); - if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL. + if ($domain == 'flickr.com' || endsWith($domain, '.flickr.com') + || $domain == 'vimeo.com' + || $domain == 'ted.com' || endsWith($domain, '.ted.com') + || $domain == 'xkcd.com' || endsWith($domain, '.xkcd.com') + ) { + if ($domain == 'vimeo.com') { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric) + $path = parse_url($url, PHP_URL_PATH); + if (!preg_match('!/\d+.+?!', $path)) { + return array(); + } // This is not a single video URL. } - if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) - { // Make sure this url points to a single comic (/xxx... where xxx is numeric) - $path = parse_url($url,PHP_URL_PATH); - if (!preg_match('!/\d+.+?!',$path)) return array(); + if ($domain == 'xkcd.com' || endsWith($domain, '.xkcd.com')) { // Make sure this url points to a single comic (/xxx... where xxx is numeric) + $path = parse_url($url, PHP_URL_PATH); + if (!preg_match('!/\d+.+?!', $path)) { + return array(); + } } - if ($domain=='ted.com' || endsWith($domain,'.ted.com')) - { // Make sure this TED url points to a video (/talks/...) - $path = parse_url($url,PHP_URL_PATH); - if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. + if ($domain == 'ted.com' || endsWith($domain, '.ted.com')) { // Make sure this TED url points to a video (/talks/...) + $path = parse_url($url, PHP_URL_PATH); + if ('/talks/' !== substr($path, 0, 7)) { + return array(); + } // This is not a single video URL. } $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) - return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.rawurlencode($url), - 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); + return array('src' => indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.rawurlencode($url), + 'href' => $href, 'width' => '120', 'style' => 'height:auto;', 'alt' => 'thumbnail', ); } // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif // Technically speaking, we should download ALL links and check their Content-Type to see if they are images. // But using the extension will do. - $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); - if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') - { + $ext = strtolower(pathinfo($url, PATHINFO_EXTENSION)); + if ($ext == 'jpg' || $ext == 'jpeg' || $ext == 'png' || $ext == 'gif') { $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) - return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url), - 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); + return array('src' => indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url), + 'href' => $href, 'width' => '120', 'style' => 'height:auto;', 'alt' => 'thumbnail', ); } + return array(); // No thumbnail. - } - // Returns the HTML code to display a thumbnail for a link // with a link to the original URL. // Understands various services (youtube.com...) // Input: $url = url for which the thumbnail must be found. // $href = if provided, this URL will be followed instead of $url // Returns '' if no thumbnail available. -function thumbnail($url,$href=false) +function thumbnail($url, $href = false) { - $t = computeThumbnail($url,$href); - if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. + $t = computeThumbnail($url, $href); + if (count($t) == 0) { + return ''; + } // Empty array = no thumbnail for this URL. + + $html = ''; + $html = ''; // Lazy image (only loaded by javascript when in the viewport). - if (!empty($GLOBALS['disablejquery'])) // (except if jQuery is disabled) - $html.='favicon'; - } - if(file_exists($GLOBALS['config']['CACHEDIR'].'/'.$path.'/'.$faviconHash)){ - return; - } - require_once 'inc/DataAccess.php'; - require_once 'inc/Favicon.php'; - $favicon = new \Favicon\Favicon(); - $favicon->cache(array('dir'=>'cache')); - $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; +function returnFavicon($url) +{ + if (!$GLOBALS['config']['ENABLE_FAVICON']) { + 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 'favicon'; + $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 'favicon'; + } + if (file_exists($GLOBALS['config']['CACHEDIR'].'/'.$path.'/'.$faviconHash)) { + return; + } + require_once 'inc/DataAccess.php'; + require_once 'inc/Favicon.php'; + $favicon = new \Favicon\Favicon(); + $favicon->cache(array('dir' => 'cache')); + $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 'favicon'; } // ----------------------------------------------------------------------------------------------- @@ -2249,42 +2592,40 @@ function returnFavicon($url){ function install() { // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. - if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); - + if (endsWith($_SERVER['HTTP_HOST'], '.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) { + mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions', 0705); + } // This part makes sure sessions works correctly. // (Because on some hosts, session.save_path may not be set correctly, // or we may not have write access to it.) - if (isset($_GET['test_session']) && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working')) - { // Step 2: Check if data in session is correct. + if (isset($_GET['test_session']) && (!isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested'] != 'Working')) { // Step 2: Check if data in session is correct. echo '
Sessions do not seem to work correctly on your server.
'; echo 'Make sure the variable session.save_path is set correctly in your php config, and that you have write access to it.
'; echo 'It currently points to '.session_save_path().'

Click to try again.
'; die; } - if (!isset($_SESSION['session_tested'])) - { // Step 1 : Try to store data in session and reload page. + if (!isset($_SESSION['session_tested'])) { // Step 1 : Try to store data in session and reload page. $_SESSION['session_tested'] = 'Working'; // Try to set a variable in session. header('Location: '.indexUrl().'?test_session'); // Redirect to check stored data. } - if (isset($_GET['test_session'])) - { // Step 3: Sessions are ok. Remove test parameter from URL. + if (isset($_GET['test_session'])) { // Step 3: Sessions are ok. Remove test parameter from URL. header('Location: '.indexUrl()); } - - if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) - { + if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) { $tz = 'UTC'; - if (!empty($_POST['continent']) && !empty($_POST['city'])) - if (isTZvalid($_POST['continent'],$_POST['city'])) + if (!empty($_POST['continent']) && !empty($_POST['city'])) { + if (isTZvalid($_POST['continent'], $_POST['city'])) { $tz = $_POST['continent'].'/'.$_POST['city']; + } + } $GLOBALS['timezone'] = $tz; // Everything is ok, let's create config file. $GLOBALS['login'] = $_POST['setlogin']; - $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. + $GLOBALS['salt'] = sha1(uniqid('', true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); - $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] ); + $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title']); $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); writeConfig(); echo ''; @@ -2292,12 +2633,15 @@ function install() } // Display config form: - list($timezone_form,$timezone_js) = templateTZform(); - $timezone_html=''; if ($timezone_form!='') $timezone_html='Timezone:'.$timezone_form.''; + list($timezone_form, $timezone_js) = templateTZform(); + $timezone_html = ''; + if ($timezone_form != '') { + $timezone_html = 'Timezone:'.$timezone_form.''; + } - $PAGE = new pageBuilder; - $PAGE->assign('timezone_html',$timezone_html); - $PAGE->assign('timezone_js',$timezone_js); + $PAGE = new pageBuilder(); + $PAGE->assign('timezone_html', $timezone_html); + $PAGE->assign('timezone_js', $timezone_js); $PAGE->renderPage('install'); exit; } @@ -2307,13 +2651,19 @@ function install() // Output: array(html,js) // Example: list($htmlform,$js) = templateTZform('Europe/Paris'); // Europe/Paris pre-selected. // Returns array('','') if server does not support timezones list. (eg. php 5.1 on free.fr) -function templateTZform($ptz=false) +function templateTZform($ptz = false) { - if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr - { + if (function_exists('timezone_identifiers_list')) { + // because of old php version (5.1) which can be found on free.fr + // Try to split the provided timezone. - if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; } - $spos=strpos($ptz,'/'); $pcontinent=substr($ptz,0,$spos); $pcity=substr($ptz,$spos+1); + if ($ptz == false) { + $l = timezone_identifiers_list(); + $ptz = $l[0]; + } + $spos = strpos($ptz, '/'); + $pcontinent = substr($ptz, 0, $spos); + $pcity = substr($ptz, $spos + 1); // Display config form: $timezone_form = ''; $timezone_js = ''; @@ -2321,44 +2671,53 @@ function templateTZform($ptz=false) // We split the list in continents/cities. $continents = array(); $cities = array(); - foreach(timezone_identifiers_list() as $tz) - { - if ($tz=='UTC') $tz='UTC/UTC'; - $spos = strpos($tz,'/'); - if ($spos!==false) - { - $continent=substr($tz,0,$spos); $city=substr($tz,$spos+1); - $continents[$continent]=1; - if (!isset($cities[$continent])) $cities[$continent]=''; - $cities[$continent].=''; + foreach (timezone_identifiers_list() as $tz) { + if ($tz == 'UTC') { + $tz = 'UTC/UTC'; + } + $spos = strpos($tz, '/'); + if ($spos !== false) { + $continent = substr($tz, 0, $spos); + $city = substr($tz, $spos + 1); + $continents[$continent] = 1; + if (!isset($cities[$continent])) { + $cities[$continent] = ''; + } + $cities[$continent] .= ''; } } $continents_html = ''; $continents = array_keys($continents); - foreach($continents as $continent) - $continents_html.=''; + foreach ($continents as $continent) { + $continents_html .= ''; + } $cities_html = $cities[$pcontinent]; $timezone_form = "Continent: "; $timezone_form .= "    City:
"; - $timezone_js = "" ; - return array($timezone_form,$timezone_js); + $timezone_js = ''; + + return array($timezone_form, $timezone_js); } - return array('',''); + + return array('', ''); } // Tells if a timezone is valid or not. // If not valid, returns false. // If system does not support timezone list, returns false. -function isTZvalid($continent,$city) +function isTZvalid($continent, $city) { $tz = $continent.'/'.$city; - if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr - { - if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone ? + if (function_exists('timezone_identifiers_list')) { + // because of old php version (5.1) which can be found on free.fr + + if (in_array($tz, timezone_identifiers_list())) { // it's a valid timezone ? return true; + } } + return false; } @@ -2366,44 +2725,56 @@ function isTZvalid($continent,$city) // eg. index.php?ws=tags&term=minecr function processWS() { - if (empty($_GET['ws']) || empty($_GET['term'])) return; + if (empty($_GET['ws']) || empty($_GET['term'])) { + return; + } $term = $_GET['term']; - $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). + $LINKSDB = new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). header('Content-Type: application/json; charset=utf-8'); // Search in tags (case insentitive, cumulative search) - if ($_GET['ws']=='tags') - { - $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") - $addtags=''; if ($tags) $addtags=implode(' ',$tags).' '; // We will pre-pend previous tags - $suggested=array(); + if ($_GET['ws'] == 'tags') { + $tags = explode(' ', str_replace(',', ' ', $term)); + $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") + $addtags = ''; + if ($tags) { + $addtags = implode(' ', $tags).' '; + } // We will pre-pend previous tags + $suggested = array(); /* To speed up things, we store list of tags in session */ - if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); - foreach($_SESSION['tags'] as $key=>$value) - { - if (startsWith($key,$last,$case=false) && !in_array($key,$tags)) $suggested[$addtags.$key.' ']=0; + if (empty($_SESSION['tags'])) { + $_SESSION['tags'] = $LINKSDB->allTags(); + } + foreach ($_SESSION['tags'] as $key => $value) { + if (startsWith($key, $last, $case = false) && !in_array($key, $tags)) { + $suggested[$addtags.$key.' '] = 0; + } } echo json_encode(array_keys($suggested)); exit; } // Search a single tag (case sentitive, single tag search) - if ($_GET['ws']=='singletag') - { + if ($_GET['ws'] == 'singletag') { /* To speed up things, we store list of tags in session */ - if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); - foreach($_SESSION['tags'] as $key=>$value) - { - if (startsWith($key,$term,$case=true)) $suggested[$key]=0; + if (empty($_SESSION['tags'])) { + $_SESSION['tags'] = $LINKSDB->allTags(); + } + foreach ($_SESSION['tags'] as $key => $value) { + if (startsWith($key, $term, $case = true)) { + $suggested[$key] = 0; + } } echo json_encode(array_keys($suggested)); exit; } } -function getAllTheme(){ - $allTheme = glob('tpl/*', GLOB_ONLYDIR); - foreach ($allTheme as $value) { - $themes[] = str_replace('tpl/', '', $value); - } - return $themes; +function getAllTheme() +{ + $allTheme = glob('tpl/*', GLOB_ONLYDIR); + foreach ($allTheme as $value) { + $themes[] = str_replace('tpl/', '', $value); + } + + return $themes; } // Re-write configuration file according to globals. // Requires some $GLOBALS to be set (login,hash,salt,title). @@ -2411,22 +2782,24 @@ function getAllTheme(){ // (otherwise, the function simply returns.) function writeConfig() { - if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. + if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) { + die('You are not authorized to alter config.'); + } // Only logged in user can alter config. $config = "alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';'; exit; } @@ -2458,175 +2830,157 @@ function genThumbnail() { // Make sure the parameters in the URL were generated by us. $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']); - if ($sign!=$_GET['hmac']) die('Naughty boy !'); + if ($sign != $_GET['hmac']) { + die('Naughty boy !'); + } // Let's see if we don't already have the image for this URL in the cache. - $thumbname=hash('sha1',$_GET['url']).'.jpg'; - if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$thumbname)) - { // We have the thumbnail, just serve it: + $thumbname = hash('sha1', $_GET['url']).'.jpg'; + if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$thumbname)) { // We have the thumbnail, just serve it: header('Content-Type: image/jpeg'); echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname); + return; } // We may also serve a blank image (if service did not respond) - $blankname=hash('sha1',$_GET['url']).'.gif'; - if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$blankname)) - { + $blankname = hash('sha1', $_GET['url']).'.gif'; + if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$blankname)) { header('Content-Type: image/gif'); echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname); + return; } // Otherwise, generate the thumbnail. $url = $_GET['url']; - $domain = parse_url($url,PHP_URL_HOST); + $domain = parse_url($url, PHP_URL_HOST); - if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')) - { + if ($domain == 'flickr.com' || endsWith($domain, '.flickr.com')) { // Crude replacement to handle new Flickr domain policy (They prefer www. now) - $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url); + $url = str_replace('http://flickr.com/', 'http://www.flickr.com/', $url); // Is this a link to an image, or to a flickr page ? - $imageurl=''; - if (endswith(parse_url($url,PHP_URL_PATH),'.jpg')) - { // This is a direct link to an image. eg. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg - preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); - if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; - } - else // this is a flickr page (html) - { - list($httpstatus,$headers,$data) = getHTTP($url,20); // Get the flickr html page. - if (strpos($httpstatus,'200 OK')!==false) - { + $imageurl = ''; + if (endswith(parse_url($url, PHP_URL_PATH), '.jpg')) { // This is a direct link to an image. eg. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg + preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!', $url, $matches); + if (!empty($matches[1])) { + $imageurl = $matches[1].'m.jpg'; + } + } else { + // this is a flickr page (html) + + list($httpstatus, $headers, $data) = getHTTP($url, 20); // Get the flickr html page. + if (strpos($httpstatus, '200 OK') !== false) { // Flickr now nicely provides the URL of the thumbnail in each flickr page. - preg_match('! - if ($imageurl=='') - { - preg_match('! tag on that page // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html // - list($httpstatus,$headers,$data) = getHTTP($url,5); - if (strpos($httpstatus,'200 OK')!==false) - { + list($httpstatus, $headers, $data) = getHTTP($url, 5); + if (strpos($httpstatus, '200 OK') !== false) { // Extract the link to the thumbnail - preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!',$data,$matches); - if (!empty($matches[1])) - { // Let's download the image. - $imageurl=$matches[1]; - list($httpstatus,$headers,$data) = getHTTP($imageurl,20); // No control on image size, so wait long enough. - if (strpos($httpstatus,'200 OK')!==false) - { - $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; - file_put_contents($filepath,$data); // Save image to cache. - if (resizeImage($filepath)) - { + preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!', $data, $matches); + if (!empty($matches[1])) { // Let's download the image. + $imageurl = $matches[1]; + list($httpstatus, $headers, $data) = getHTTP($imageurl, 20); // No control on image size, so wait long enough. + if (strpos($httpstatus, '200 OK') !== false) { + $filepath = $GLOBALS['config']['CACHEDIR'].'/'.$thumbname; + file_put_contents($filepath, $data); // Save image to cache. + if (resizeImage($filepath)) { header('Content-Type: image/jpeg'); echo file_get_contents($filepath); + return; } } } } - } - - elseif ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) - { + } elseif ($domain == 'xkcd.com' || endsWith($domain, '.xkcd.com')) { // There is no thumbnail available for xkcd comics, so download the whole image and resize it. // http://xkcd.com/327/ // <BLABLA> - list($httpstatus,$headers,$data) = getHTTP($url,5); - if (strpos($httpstatus,'200 OK')!==false) - { + list($httpstatus, $headers, $data) = getHTTP($url, 5); + if (strpos($httpstatus, '200 OK') !== false) { // Extract the link to the thumbnail - preg_match('! From 34b2678fd9c263dd232a39d95e18314934e3d926 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Tue, 14 Jun 2016 11:41:43 +0200 Subject: [PATCH 11/14] [fix] bad link for myShaarli repo --- tpl/myShaarli/page.footer.html | 28 ++++++++++++-------------- tpl/myShaarli_Columns/page.footer.html | 28 ++++++++++++-------------- tpl/original/page.footer.html | 28 ++++++++++++-------------- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/tpl/myShaarli/page.footer.html b/tpl/myShaarli/page.footer.html index a0a1198..6558b7b 100644 --- a/tpl/myShaarli/page.footer.html +++ b/tpl/myShaarli/page.footer.html @@ -1,23 +1,21 @@ {if="$newversion"} -{/if} -{if="isLoggedIn()"} +{/if} {if="isLoggedIn()"} {/if} diff --git a/tpl/myShaarli_Columns/page.footer.html b/tpl/myShaarli_Columns/page.footer.html index a0a1198..6558b7b 100644 --- a/tpl/myShaarli_Columns/page.footer.html +++ b/tpl/myShaarli_Columns/page.footer.html @@ -1,23 +1,21 @@ {if="$newversion"} -{/if} -{if="isLoggedIn()"} +{/if} {if="isLoggedIn()"} {/if} diff --git a/tpl/original/page.footer.html b/tpl/original/page.footer.html index b4cdac3..eca499f 100644 --- a/tpl/original/page.footer.html +++ b/tpl/original/page.footer.html @@ -1,23 +1,21 @@ {if="$newversion"} -{/if} -{if="isLoggedIn()"} +{/if} {if="isLoggedIn()"} {/if} From 5ac350359c988602cc2ed9e6c4507e567d589408 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Tue, 14 Jun 2016 11:59:10 +0200 Subject: [PATCH 12/14] [fix] private icon not show --- tpl/myShaarli/myShaarli.css | 7 +++++-- tpl/myShaarli_Columns/columns.css | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tpl/myShaarli/myShaarli.css b/tpl/myShaarli/myShaarli.css index 2cf9b8d..ed391d7 100644 --- a/tpl/myShaarli/myShaarli.css +++ b/tpl/myShaarli/myShaarli.css @@ -518,12 +518,15 @@ a, .linkdescription a { } #linklist li, #linklist li.private { - background: #fff; + background-color: #fff; + background-image: url('../../images/private_16x16.png'); + background-repeat: no-repeat; + background-position: 10px center; border: 1px solid #cdcdcd; border-radius: .3em; clear: both; margin: 1em 0; - padding: .3em; + padding: .3em .3em .3em 32px; } #linklist li.publicLinkHightLight { diff --git a/tpl/myShaarli_Columns/columns.css b/tpl/myShaarli_Columns/columns.css index e1f5a57..c9ea191 100644 --- a/tpl/myShaarli_Columns/columns.css +++ b/tpl/myShaarli_Columns/columns.css @@ -528,7 +528,10 @@ a, .linkdescription a { #linklist li, #linklist li.private { box-sizing: border-box; - background: #fff; + background-color: #fff; + background-image: url('../../images/private_16x16.png'); + background-repeat: no-repeat; + background-position: 10px 10px; border: 1px solid #cdcdcd; border-radius: .3em; flex: 0 0 auto; @@ -1286,4 +1289,4 @@ a:hover, .linkdescription a:hover, .linktitle a:hover, .linkWallabag a:hover, .l position: relative; width: calc(100% - 0.6em); } -} \ No newline at end of file +} From 9a494867078ffb203a290f9a694b1885efcd941b Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Tue, 14 Jun 2016 12:01:23 +0200 Subject: [PATCH 13/14] Bump version --- index.php | 2 +- shaarli_version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.php b/index.php index 498b886..97c7fbe 100644 --- a/index.php +++ b/index.php @@ -54,7 +54,7 @@ if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) { require $GLOBALS['config']['DATADIR'].'/options.php'; } -define('myShaarli_version', '1.1.3'); +define('myShaarli_version', '1.1.4'); define('PHPPREFIX', ''); // Suffix to encapsulate data in php code. // http://server.com/x/shaarli --> /shaarli/ diff --git a/shaarli_version.txt b/shaarli_version.txt index 781dcb0..65087b4 100644 --- a/shaarli_version.txt +++ b/shaarli_version.txt @@ -1 +1 @@ -1.1.3 +1.1.4 From e9cda12d817b88f636fa6e1d7cbc0e470e30a085 Mon Sep 17 00:00:00 2001 From: Knah Tsaeb Date: Wed, 15 Jun 2016 09:10:11 +0200 Subject: [PATCH 14/14] [fix] private icon not show --- tpl/myShaarli/myShaarli.css | 12 ++++++++---- tpl/myShaarli_Columns/columns.css | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tpl/myShaarli/myShaarli.css b/tpl/myShaarli/myShaarli.css index ed391d7..83bdf14 100644 --- a/tpl/myShaarli/myShaarli.css +++ b/tpl/myShaarli/myShaarli.css @@ -519,14 +519,18 @@ a, .linkdescription a { #linklist li, #linklist li.private { background-color: #fff; - background-image: url('../../images/private_16x16.png'); - background-repeat: no-repeat; - background-position: 10px center; border: 1px solid #cdcdcd; border-radius: .3em; clear: both; margin: 1em 0; - padding: .3em .3em .3em 32px; + padding: .3em; +} + +#linklist li.private { + background-image: url('../../images/private_16x16.png'); + background-repeat: no-repeat; + background-position: 10px center; + padding: .3em .3em .3em 32px; } #linklist li.publicLinkHightLight { diff --git a/tpl/myShaarli_Columns/columns.css b/tpl/myShaarli_Columns/columns.css index c9ea191..fab3b4e 100644 --- a/tpl/myShaarli_Columns/columns.css +++ b/tpl/myShaarli_Columns/columns.css @@ -529,9 +529,6 @@ a, .linkdescription a { #linklist li, #linklist li.private { box-sizing: border-box; background-color: #fff; - background-image: url('../../images/private_16x16.png'); - background-repeat: no-repeat; - background-position: 10px 10px; border: 1px solid #cdcdcd; border-radius: .3em; flex: 0 0 auto; @@ -541,6 +538,12 @@ a, .linkdescription a { width: calc(25% - .6em); } +#linklist li.private { + background-image: url('../../images/private_16x16.png'); + background-repeat: no-repeat; + background-position: 10px 10px; +} + #linklist li.publicLinkHightLight { background: #ffffff; }