aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornodiscc <nodiscc@gmail.com>2014-08-11 20:41:50 +0200
committernodiscc <nodiscc@gmail.com>2014-08-19 18:01:15 +0200
commitad6c27b7b858dfa29e65f14ef444fad318d5895b (patch)
tree29297748c42189aec25a857fba53d4c95560c616
parente411f7f9d7682256fdba017d409e8356c4644ab9 (diff)
downloadShaarli-ad6c27b7b858dfa29e65f14ef444fad318d5895b.tar.gz
Shaarli-ad6c27b7b858dfa29e65f14ef444fad318d5895b.tar.zst
Shaarli-ad6c27b7b858dfa29e65f14ef444fad318d5895b.zip
Fix grammar, punctuation, spelling, trailing whitepaces and newlines; Fix typo in css
Based on respencer's work at https://github.com/respencer/Shaarli/ Closes https://github.com/sebsauvage/Shaarli/pull/103
-rw-r--r--README.md4
-rw-r--r--inc/shaarli.css10
-rw-r--r--index.php254
-rw-r--r--tpl/configure.html4
-rw-r--r--tpl/import.html2
5 files changed, 137 insertions, 137 deletions
diff --git a/README.md b/README.md
index cff718cf..a89d577f 100644
--- a/README.md
+++ b/README.md
@@ -12,12 +12,12 @@ Features:
12 * **FAST** 12 * **FAST**
13 * Dead-simple installation: Drop the files, open the page. No database required. 13 * Dead-simple installation: Drop the files, open the page. No database required.
14 * Easy to use: Single button in your browser to bookmark a page 14 * Easy to use: Single button in your browser to bookmark a page
15 * Save url, title, description (unlimited size). Classify links with tags (with autocomplete) 15 * Save URL, title, description (unlimited size). Classify links with tags (with autocomplete)
16 * Tag renaming, merging and deletion. 16 * Tag renaming, merging and deletion.
17 * Automatic thumbnails for various services (imgur, imageshack.us, flickr, youtube, vimeo, dailymotion…) 17 * Automatic thumbnails for various services (imgur, imageshack.us, flickr, youtube, vimeo, dailymotion…)
18 * Automatic conversion of URLs to clickable links in descriptions. Support for http/ftp/file/apt/magnet protocols. 18 * Automatic conversion of URLs to clickable links in descriptions. Support for http/ftp/file/apt/magnet protocols.
19 * Save links as public or private 19 * Save links as public or private
20 * 1-clic access to your private links/notes 20 * 1-click access to your private links/notes
21 * Browse links by page, filter by tag or use the full text search engine 21 * Browse links by page, filter by tag or use the full text search engine
22 * Permalinks (with QR-Code) for easy reference 22 * Permalinks (with QR-Code) for easy reference
23 * RSS and ATOM feeds (which can be filtered by tag or text search) 23 * RSS and ATOM feeds (which can be filtered by tag or text search)
diff --git a/inc/shaarli.css b/inc/shaarli.css
index cdc05790..13e6ab33 100644
--- a/inc/shaarli.css
+++ b/inc/shaarli.css
@@ -1,4 +1,4 @@
1/* CSS Stylsheet for Shaarli - http://sebsauvage.net/wiki/doku.php?id=php:shaarli */ 1/* Cascading Stylesheet for Shaarli - http://sebsauvage.net/wiki/doku.php?id=php:shaarli */
2 2
3/* CSS Reset from Yahoo to cope with browsers CSS inconsistencies. */ 3/* CSS Reset from Yahoo to cope with browsers CSS inconsistencies. */
4/* 4/*
@@ -408,13 +408,13 @@ div.dailyEntryDescription
408 overflow:auto; 408 overflow:auto;
409} 409}
410 410
411/* Common css screwdriver */ 411/* Common CSS screwdriver */
412.clear{ 412.clear{
413 clear:both; 413 clear:both;
414} 414}
415 415
416/* For lazy images loading in picture wall. 416/* For lazy images loading in picture wall.
417 using http://www.appelsiini.net/projects/lazyload 417 Using http://www.appelsiini.net/projects/lazyload
418 */ 418 */
419.lazyimage { display:none; } 419.lazyimage { display:none; }
420 420
@@ -451,7 +451,7 @@ a {color:#000!important;text-decoration:none!important;}
451#searchform_value { width:70% !important; } 451#searchform_value { width:70% !important; }
452#tagfilter_value { width:70% !important; } 452#tagfilter_value { width:70% !important; }
453div.qrcode { position:relative; float:left; top:-10px; left:0px; } 453div.qrcode { position:relative; float:left; top:-10px; left:0px; }
454#paging_privatelinks { float;none; } 454#paging_privatelinks { float:none; }
455#paging_linksperpage { float:none; margin-bottom:10px; font-size:smaller;} 455#paging_linksperpage { float:none; margin-bottom:10px; font-size:smaller;}
456#paging_older,#paging_newer,#paging_linksperpage a { border: 1px solid black; padding:3px 5px 3px 5px; background-color:#666; color:#fff; border-radius: 5px 5px 5px 5px;} 456#paging_older,#paging_newer,#paging_linksperpage a { border: 1px solid black; padding:3px 5px 3px 5px; background-color:#666; color:#fff; border-radius: 5px 5px 5px 5px;}
457.thumbnail { float:none; height:auto; margin: 0px; text-align:center;} 457.thumbnail { float:none; height:auto; margin: 0px; text-align:center;}
@@ -466,4 +466,4 @@ div.dailyEntryDescription { font-size:10pt; }
466} 466}
467 467
468/* Highlight search results */ 468/* Highlight search results */
469.highlight { background-color: #FFFF33; } 469.highlight { background-color: #FFFF33; } \ No newline at end of file
diff --git a/index.php b/index.php
index 5dd0353b..07f877de 100644
--- a/index.php
+++ b/index.php
@@ -1,9 +1,9 @@
1<?php 1<?php
2// Shaarli 0.0.42 beta - Shaare your links... 2// Shaarli 0.0.42 beta - Shaare your links...
3// The personal, minimalist, super-fast, no-database delicious clone. By sebsauvage.net 3// The personal, minimalist, super-fast, no-database Delicious clone. By sebsauvage.net
4// http://sebsauvage.net/wiki/doku.php?id=php:shaarli 4// http://sebsauvage.net/wiki/doku.php?id=php:shaarli
5// Licence: http://www.opensource.org/licenses/zlib-license.php 5// Licence: http://www.opensource.org/licenses/zlib-license.php
6// Requires: php 5.1.x (but autocomplete fields will only work if you have php 5.2.x) 6// Requires: PHP 5.1.x (but autocomplete fields will only work if you have PHP 5.2.x)
7// ----------------------------------------------------------------------------------------------- 7// -----------------------------------------------------------------------------------------------
8// NEVER TRUST IN PHP.INI 8// NEVER TRUST IN PHP.INI
9// Some hosts do not define a default timezone in php.ini, 9// Some hosts do not define a default timezone in php.ini,
@@ -24,19 +24,19 @@ $GLOBALS['config']['HIDE_TIMESTAMPS'] = false; // If true, the moment when links
24$GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links. 24$GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links.
25$GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr) 25$GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr)
26$GLOBALS['config']['PAGECACHE'] = 'pagecache'; // Page cache directory. 26$GLOBALS['config']['PAGECACHE'] = 'pagecache'; // Page cache directory.
27$GLOBALS['config']['ENABLE_LOCALCACHE'] = true; // Enable Shaarli to store thumbnail in a local cache. Disable to reduce webspace usage. 27$GLOBALS['config']['ENABLE_LOCALCACHE'] = true; // Enable Shaarli to store thumbnail in a local cache. Disable to reduce web space usage.
28$GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable. 28$GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable.
29$GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli. 29$GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli.
30$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours 30$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours
31 // Note: You must have publisher.php in the same directory as Shaarli index.php 31 // Note: You must have publisher.php in the same directory as Shaarli index.php
32// ----------------------------------------------------------------------------------------------- 32// -----------------------------------------------------------------------------------------------
33// You should not touch below (or at your own risks !) 33// You should not touch below (or at your own risks!)
34// Optionnal config file. 34// Optional config file.
35if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); 35if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php');
36 36
37define('shaarli_version','0.0.42 beta'); 37define('shaarli_version','0.0.42 beta');
38define('PHPPREFIX','<?php /* '); // Prefix to encapsulate data in php code. 38define('PHPPREFIX','<?php /* '); // Prefix to encapsulate data in PHP code.
39define('PHPSUFFIX',' */ ?>'); // Suffix to encapsulate data in php code. 39define('PHPSUFFIX',' */ ?>'); // Suffix to encapsulate data in PHP code.
40// http://server.com/x/shaarli --> /shaarli/ 40// http://server.com/x/shaarli --> /shaarli/
41define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); 41define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0)));
42 42
@@ -48,8 +48,8 @@ session_set_cookie_params($cookie['lifetime'],$cookiedir,$_SERVER['HTTP_HOST']);
48// Set session parameters on server side. 48// Set session parameters on server side.
49define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired. 49define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired.
50ini_set('session.use_cookies', 1); // Use cookies to store session. 50ini_set('session.use_cookies', 1); // Use cookies to store session.
51ini_set('session.use_only_cookies', 1); // Force cookies for session (phpsessionID forbidden in URL) 51ini_set('session.use_only_cookies', 1); // Force cookies for session (phpsessionID forbidden in URL).
52ini_set('session.use_trans_sid', false); // Prevent php to use sessionID in URL if cookies are disabled. 52ini_set('session.use_trans_sid', false); // Prevent PHP form using sessionID in URL if cookies are disabled.
53session_name('shaarli'); 53session_name('shaarli');
54if (session_id() == '') session_start(); // Start session if needed (Some server auto-start sessions). 54if (session_id() == '') session_start(); // Start session if needed (Some server auto-start sessions).
55 55
@@ -85,7 +85,7 @@ header("Cache-Control: no-store, no-cache, must-revalidate");
85header("Cache-Control: post-check=0, pre-check=0", false); 85header("Cache-Control: post-check=0, pre-check=0", false);
86header("Pragma: no-cache"); 86header("Pragma: no-cache");
87 87
88// Directories creations (Note that your web host may require differents rights than 705.) 88// Directories creations (Note that your web host may require different rights than 705.)
89if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory ('.realpath(dirname(__FILE__)).').</pre>'); 89if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory ('.realpath(dirname(__FILE__)).').</pre>');
90if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } 90if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); }
91if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } // For RainTPL temporary files. 91if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } // For RainTPL temporary files.
@@ -119,13 +119,13 @@ define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GL
119autoLocale(); // Sniff browser language and set date format accordingly. 119autoLocale(); // Sniff browser language and set date format accordingly.
120header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. 120header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling.
121 121
122// Check php version 122// Check PHP version
123function checkphpversion() 123function checkphpversion()
124{ 124{
125 if (version_compare(PHP_VERSION, '5.1.0') < 0) 125 if (version_compare(PHP_VERSION, '5.1.0') < 0)
126 { 126 {
127 header('Content-Type: text/plain; charset=utf-8'); 127 header('Content-Type: text/plain; charset=utf-8');
128 echo 'Your server supports php '.PHP_VERSION.'. Shaarli requires at least php 5.1.0, and thus cannot run. Sorry.'; 128 echo 'Your server supports PHP '.PHP_VERSION.'. Shaarli requires at least php 5.1.0, and thus cannot run. Sorry.';
129 exit; 129 exit;
130 } 130 }
131} 131}
@@ -144,7 +144,7 @@ function checkUpdate()
144 $version=shaarli_version; 144 $version=shaarli_version;
145 list($httpstatus,$headers,$data) = getHTTP('http://sebsauvage.net/files/shaarli_version.txt',2); 145 list($httpstatus,$headers,$data) = getHTTP('http://sebsauvage.net/files/shaarli_version.txt',2);
146 if (strpos($httpstatus,'200 OK')!==false) $version=$data; 146 if (strpos($httpstatus,'200 OK')!==false) $version=$data;
147 // If failed, nevermind. We don't want to bother the user with that. 147 // If failed, never mind. We don't want to bother the user with that.
148 file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date 148 file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date
149 } 149 }
150 // Compare versions: 150 // Compare versions:
@@ -160,11 +160,11 @@ function checkUpdate()
160class pageCache 160class pageCache
161{ 161{
162 private $url; // Full URL of the page to cache (typically the value returned by pageUrl()) 162 private $url; // Full URL of the page to cache (typically the value returned by pageUrl())
163 private $shouldBeCached; // boolean: Should this url be cached ? 163 private $shouldBeCached; // boolean: Should this url be cached?
164 private $filename; // Name of the cache file for this url 164 private $filename; // Name of the cache file for this url.
165 165
166 /* 166 /*
167 $url = url (typically the value returned by pageUrl()) 167 $url = URL (typically the value returned by pageUrl())
168 $shouldBeCached = boolean. If false, the cache will be disabled. 168 $shouldBeCached = boolean. If false, the cache will be disabled.
169 */ 169 */
170 public function __construct($url,$shouldBeCached) 170 public function __construct($url,$shouldBeCached)
@@ -227,7 +227,7 @@ function nl2br_escaped($html)
227} 227}
228 228
229/* Returns the small hash of a string, using RFC 4648 base64url format 229/* Returns the small hash of a string, using RFC 4648 base64url format
230 eg. smallHash('20111006_131924') --> yZH23w 230 e.g. smallHash('20111006_131924') --> yZH23w
231 Small hashes: 231 Small hashes:
232 - are unique (well, as unique as crc32, at last) 232 - are unique (well, as unique as crc32, at last)
233 - are always 6 characters long. 233 - are always 6 characters long.
@@ -241,7 +241,7 @@ function smallHash($text)
241 return strtr($t, '+/', '-_'); 241 return strtr($t, '+/', '-_');
242} 242}
243 243
244// In a string, converts urls to clickable links. 244// In a string, converts URLs to clickable links.
245// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 245// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
246function text2clickable($url) 246function text2clickable($url)
247{ 247{
@@ -262,8 +262,8 @@ function keepMultipleSpaces($text)
262function autoLocale() 262function autoLocale()
263{ 263{
264 $loc='en_US'; // Default if browser does not send HTTP_ACCEPT_LANGUAGE 264 $loc='en_US'; // Default if browser does not send HTTP_ACCEPT_LANGUAGE
265 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // eg. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3" 265 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // e.g. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3"
266 { // (It's a bit crude, but it works very well. Prefered language is always presented first.) 266 { // (It's a bit crude, but it works very well. Preferred language is always presented first.)
267 if (preg_match('/([a-z]{2}(-[a-z]{2})?)/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) $loc=$matches[1]; 267 if (preg_match('/([a-z]{2}(-[a-z]{2})?)/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) $loc=$matches[1];
268 } 268 }
269 setlocale(LC_TIME,$loc); // LC_TIME = Set local for date/time format only. 269 setlocale(LC_TIME,$loc); // LC_TIME = Set local for date/time format only.
@@ -300,7 +300,7 @@ function allIPs()
300} 300}
301 301
302function fillSessionInfo() { 302function fillSessionInfo() {
303 $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // generate unique random number (different than phpsessionid) 303 $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid)
304 $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. 304 $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked.
305 $_SESSION['username']=$GLOBALS['login']; 305 $_SESSION['username']=$GLOBALS['login'];
306 $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. 306 $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration.
@@ -404,7 +404,7 @@ if (isset($_POST['login']))
404{ 404{
405 if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.'); 405 if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.');
406 if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password']))) 406 if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password'])))
407 { // Login/password is ok. 407 { // Login/password is OK.
408 ban_loginOk(); 408 ban_loginOk();
409 // If user wants to keep the session cookie even after the browser closes: 409 // If user wants to keep the session cookie even after the browser closes:
410 if (!empty($_POST['longlastingsession'])) 410 if (!empty($_POST['longlastingsession']))
@@ -415,7 +415,7 @@ if (isset($_POST['login']))
415 415
416 $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; 416 $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/';
417 session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['HTTP_HOST']); // Set session cookie expiration on client side 417 session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['HTTP_HOST']); // Set session cookie expiration on client side
418 // Note: Never forget the trailing slash on the cookie path ! 418 // Note: Never forget the trailing slash on the cookie path!
419 session_regenerate_id(true); // Send cookie with new expiration date to browser. 419 session_regenerate_id(true); // Send cookie with new expiration date to browser.
420 } 420 }
421 else // Standard session expiration (=when browser closes) 421 else // Standard session expiration (=when browser closes)
@@ -447,7 +447,7 @@ if (isset($_POST['login']))
447// Misc utility functions: 447// Misc utility functions:
448 448
449// Returns the server URL (including port and http/https), without path. 449// Returns the server URL (including port and http/https), without path.
450// eg. "http://myserver.com:8080" 450// e.g. "http://myserver.com:8080"
451// You can append $_SERVER['SCRIPT_NAME'] to get the current script URL. 451// You can append $_SERVER['SCRIPT_NAME'] to get the current script URL.
452function serverUrl() 452function serverUrl()
453{ 453{
@@ -457,24 +457,24 @@ function serverUrl()
457} 457}
458 458
459// Returns the absolute URL of current script, without the query. 459// Returns the absolute URL of current script, without the query.
460// (eg. http://sebsauvage.net/links/) 460// (e.g. http://sebsauvage.net/links/)
461function indexUrl() 461function indexUrl()
462{ 462{
463 $scriptname = $_SERVER["SCRIPT_NAME"]; 463 $scriptname = $_SERVER["SCRIPT_NAME"];
464 // If the script is named 'index.php', we remove it (for better looking URLs, 464 // If the script is named 'index.php', we remove it (for better looking URLs,
465 // eg. http://mysite.com/shaarli/?abcde instead of http://mysite.com/shaarli/index.php?abcde) 465 // e.g. http://mysite.com/shaarli/?abcde instead of http://mysite.com/shaarli/index.php?abcde)
466 if (endswith($scriptname,'index.php')) $scriptname = substr($scriptname,0,strlen($scriptname)-9); 466 if (endswith($scriptname,'index.php')) $scriptname = substr($scriptname,0,strlen($scriptname)-9);
467 return serverUrl() . $scriptname; 467 return serverUrl() . $scriptname;
468} 468}
469 469
470// Returns the absolute URL of current script, WITH the query. 470// Returns the absolute URL of current script, WITH the query.
471// (eg. http://sebsauvage.net/links/?toto=titi&spamspamspam=humbug) 471// (e.g. http://sebsauvage.net/links/?toto=titi&spamspamspam=humbug)
472function pageUrl() 472function pageUrl()
473{ 473{
474 return indexUrl().(!empty($_SERVER["QUERY_STRING"]) ? '?'.$_SERVER["QUERY_STRING"] : ''); 474 return indexUrl().(!empty($_SERVER["QUERY_STRING"]) ? '?'.$_SERVER["QUERY_STRING"] : '');
475} 475}
476 476
477// Convert post_max_size/upload_max_filesize (eg.'16M') parameters to bytes. 477// Convert post_max_size/upload_max_filesize (e.g. '16M') parameters to bytes.
478function return_bytes($val) 478function return_bytes($val)
479{ 479{
480 $val = trim($val); $last=strtolower($val[strlen($val)-1]); 480 $val = trim($val); $last=strtolower($val[strlen($val)-1]);
@@ -495,7 +495,7 @@ function getMaxFileSize()
495 $size2 = return_bytes(ini_get('upload_max_filesize')); 495 $size2 = return_bytes(ini_get('upload_max_filesize'));
496 // Return the smaller of two: 496 // Return the smaller of two:
497 $maxsize = min($size1,$size2); 497 $maxsize = min($size1,$size2);
498 // FIXME: Then convert back to readable notations ? (eg. 2M instead of 2000000) 498 // FIXME: Then convert back to readable notations ? (e.g. 2M instead of 2000000)
499 return $maxsize; 499 return $maxsize;
500} 500}
501 501
@@ -543,7 +543,7 @@ function linkdate2iso8601($linkdate)
543function linkdate2locale($linkdate) 543function linkdate2locale($linkdate)
544{ 544{
545 return utf8_encode(strftime('%c',linkdate2timestamp($linkdate))); // %c is for automatic date format according to locale. 545 return utf8_encode(strftime('%c',linkdate2timestamp($linkdate))); // %c is for automatic date format according to locale.
546 // Note that if you use a local which is not installed on your webserver, 546 // Note that if you use a locale which is not installed on your webserver,
547 // the date will not be displayed in the chosen locale, but probably in US notation. 547 // the date will not be displayed in the chosen locale, but probably in US notation.
548} 548}
549 549
@@ -565,10 +565,10 @@ function http_parse_headers_shaarli( $headers )
565} 565}
566 566
567/* GET an URL. 567/* GET an URL.
568 Input: $url : url to get (http://...) 568 Input: $url : URL to get (http://...)
569 $timeout : Network timeout (will wait this many seconds for an anwser before giving up). 569 $timeout : Network timeout (will wait this many seconds for an anwser before giving up).
570 Output: An array. [0] = HTTP status message (eg. "HTTP/1.1 200 OK") or error message 570 Output: An array. [0] = HTTP status message (e.g. "HTTP/1.1 200 OK") or error message
571 [1] = associative array containing HTTP response headers (eg. echo getHTTP($url)[1]['Content-Type']) 571 [1] = associative array containing HTTP response headers (e.g. echo getHTTP($url)[1]['Content-Type'])
572 [2] = data 572 [2] = data
573 Example: list($httpstatus,$headers,$data) = getHTTP('http://sebauvage.net/'); 573 Example: list($httpstatus,$headers,$data) = getHTTP('http://sebauvage.net/');
574 if (strpos($httpstatus,'200 OK')!==false) 574 if (strpos($httpstatus,'200 OK')!==false)
@@ -584,11 +584,11 @@ function getHTTP($url,$timeout=30)
584 $context = stream_context_create($options); 584 $context = stream_context_create($options);
585 $data=file_get_contents($url,false,$context,-1, 4000000); // We download at most 4 Mb from source. 585 $data=file_get_contents($url,false,$context,-1, 4000000); // We download at most 4 Mb from source.
586 if (!$data) { return array('HTTP Error',array(),''); } 586 if (!$data) { return array('HTTP Error',array(),''); }
587 $httpStatus=$http_response_header[0]; // eg. "HTTP/1.1 200 OK" 587 $httpStatus=$http_response_header[0]; // e.g. "HTTP/1.1 200 OK"
588 $responseHeaders=http_parse_headers_shaarli($http_response_header); 588 $responseHeaders=http_parse_headers_shaarli($http_response_header);
589 return array($httpStatus,$responseHeaders,$data); 589 return array($httpStatus,$responseHeaders,$data);
590 } 590 }
591 catch (Exception $e) // getHTTP *can* fail silentely (we don't care if the title cannot be fetched) 591 catch (Exception $e) // getHTTP *can* fail silently (we don't care if the title cannot be fetched)
592 { 592 {
593 return array($e->getMessage(),'',''); 593 return array($e->getMessage(),'','');
594 } 594 }
@@ -614,14 +614,14 @@ function getToken()
614 return $rnd; 614 return $rnd;
615} 615}
616 616
617// Tells if a token is ok. Using this function will destroy the token. 617// Tells if a token is OK. Using this function will destroy the token.
618// true=token is ok. 618// true=token is OK.
619function tokenOk($token) 619function tokenOk($token)
620{ 620{
621 if (isset($_SESSION['tokens'][$token])) 621 if (isset($_SESSION['tokens'][$token]))
622 { 622 {
623 unset($_SESSION['tokens'][$token]); // Token is used: destroy it. 623 unset($_SESSION['tokens'][$token]); // Token is used: destroy it.
624 return true; // Token is ok. 624 return true; // Token is OK.
625 } 625 }
626 return false; // Wrong token, or already used. 626 return false; // Wrong token, or already used.
627} 627}
@@ -656,7 +656,7 @@ class pageBuilder
656 $this->tpl->assign('version',shaarli_version); 656 $this->tpl->assign('version',shaarli_version);
657 $this->tpl->assign('scripturl',indexUrl()); 657 $this->tpl->assign('scripturl',indexUrl());
658 $this->tpl->assign('pagetitle','Shaarli'); 658 $this->tpl->assign('pagetitle','Shaarli');
659 $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ? 659 $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links?
660 if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']); 660 if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
661 if (!empty($GLOBALS['titleLink'])) $this->tpl->assign('titleLink',$GLOBALS['titleLink']); 661 if (!empty($GLOBALS['titleLink'])) $this->tpl->assign('titleLink',$GLOBALS['titleLink']);
662 if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']); 662 if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
@@ -672,7 +672,7 @@ class pageBuilder
672 } 672 }
673 673
674 // Render a specific page (using a template). 674 // Render a specific page (using a template).
675 // eg. pb.renderPage('picwall') 675 // e.g. pb.renderPage('picwall')
676 public function renderPage($page) 676 public function renderPage($page)
677 { 677 {
678 if ($this->tpl===false) $this->initialize(); // Lazy initialization 678 if ($this->tpl===false) $this->initialize(); // Lazy initialization
@@ -691,10 +691,10 @@ class pageBuilder
691 691
692 Available keys: 692 Available keys:
693 title : Title of the link 693 title : Title of the link
694 url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (eg.'?m-ukcw') 694 url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (e.g.'?m-ukcw')
695 description : description of the entry 695 description : description of the entry
696 private : Is this link private ? 0=no, other value=yes 696 private : Is this link private? 0=no, other value=yes
697 linkdate : date of the creation of this entry, in the form YYYYMMDD_HHMMSS (eg.'20110914_192317') 697 linkdate : date of the creation of this entry, in the form YYYYMMDD_HHMMSS (e.g.'20110914_192317')
698 tags : tags attached to this entry (separated by spaces) 698 tags : tags attached to this entry (separated by spaces)
699 699
700 We implement 3 interfaces: 700 We implement 3 interfaces:
@@ -704,15 +704,15 @@ class pageBuilder
704*/ 704*/
705class linkdb implements Iterator, Countable, ArrayAccess 705class linkdb implements Iterator, Countable, ArrayAccess
706{ 706{
707 private $links; // List of links (associative array. Key=linkdate (eg. "20110823_124546"), value= associative array (keys:title,description...) 707 private $links; // List of links (associative array. Key=linkdate (e.g. "20110823_124546"), value= associative array (keys:title,description...)
708 private $urls; // List of all recorded URLs (key=url, value=linkdate) for fast reserve search (url-->linkdate) 708 private $urls; // List of all recorded URLs (key=url, value=linkdate) for fast reserve search (url-->linkdate)
709 private $keys; // List of linkdate keys (for the Iterator interface implementation) 709 private $keys; // List of linkdate keys (for the Iterator interface implementation)
710 private $position; // Position in the $this->keys array. (for the Iterator interface implementation.) 710 private $position; // Position in the $this->keys array. (for the Iterator interface implementation.)
711 private $loggedin; // Is the used logged in ? (used to filter private links) 711 private $loggedin; // Is the user logged in? (used to filter private links)
712 712
713 // Constructor: 713 // Constructor:
714 function __construct($isLoggedIn) 714 function __construct($isLoggedIn)
715 // Input : $isLoggedIn : is the used logged in ? 715 // Input : $isLoggedIn : is the user logged in?
716 { 716 {
717 $this->loggedin = $isLoggedIn; 717 $this->loggedin = $isLoggedIn;
718 $this->checkdb(); // Make sure data file exists. 718 $this->checkdb(); // Make sure data file exists.
@@ -726,7 +726,7 @@ class linkdb implements Iterator, Countable, ArrayAccess
726 public function offsetSet($offset, $value) 726 public function offsetSet($offset, $value)
727 { 727 {
728 if (!$this->loggedin) die('You are not authorized to add a link.'); 728 if (!$this->loggedin) die('You are not authorized to add a link.');
729 if (empty($value['linkdate']) || empty($value['url'])) die('Internal Error: A link should always have a linkdate and url.'); 729 if (empty($value['linkdate']) || empty($value['url'])) die('Internal Error: A link should always have a linkdate and URL.');
730 if (empty($offset)) die('You must specify a key.'); 730 if (empty($offset)) die('You must specify a key.');
731 $this->links[$offset] = $value; 731 $this->links[$offset] = $value;
732 $this->urls[$value['url']]=$offset; 732 $this->urls[$value['url']]=$offset;
@@ -789,19 +789,19 @@ class linkdb implements Iterator, Countable, ArrayAccess
789 invalidateCaches(); 789 invalidateCaches();
790 } 790 }
791 791
792 // Returns the link for a given URL (if it exists). false it does not exist. 792 // Returns the link for a given URL (if it exists). False if it does not exist.
793 public function getLinkFromUrl($url) 793 public function getLinkFromUrl($url)
794 { 794 {
795 if (isset($this->urls[$url])) return $this->links[$this->urls[$url]]; 795 if (isset($this->urls[$url])) return $this->links[$this->urls[$url]];
796 return false; 796 return false;
797 } 797 }
798 798
799 // Case insentitive search among links (in url, title and description). Returns filtered list of links. 799 // Case insensitive search among links (in the URLs, title and description). Returns filtered list of links.
800 // eg. print_r($mydb->filterFulltext('hollandais')); 800 // e.g. print_r($mydb->filterFulltext('hollandais'));
801 public function filterFulltext($searchterms) 801 public function filterFulltext($searchterms)
802 { 802 {
803 // FIXME: explode(' ',$searchterms) and perform a AND search. 803 // FIXME: explode(' ',$searchterms) and perform a AND search.
804 // FIXME: accept double-quotes to search for a string "as is" ? 804 // FIXME: accept double-quotes to search for a string "as is"?
805 $filtered=array(); 805 $filtered=array();
806 $s = strtolower($searchterms); 806 $s = strtolower($searchterms);
807 foreach($this->links as $l) 807 foreach($this->links as $l)
@@ -818,7 +818,7 @@ class linkdb implements Iterator, Countable, ArrayAccess
818 818
819 // Filter by tag. 819 // Filter by tag.
820 // You can specify one or more tags (tags can be separated by space or comma). 820 // You can specify one or more tags (tags can be separated by space or comma).
821 // eg. print_r($mydb->filterTags('linux programming')); 821 // e.g. print_r($mydb->filterTags('linux programming'));
822 public function filterTags($tags,$casesensitive=false) 822 public function filterTags($tags,$casesensitive=false)
823 { 823 {
824 $t = str_replace(',',' ',($casesensitive?$tags:strtolower($tags))); 824 $t = str_replace(',',' ',($casesensitive?$tags:strtolower($tags)));
@@ -834,9 +834,9 @@ class linkdb implements Iterator, Countable, ArrayAccess
834 return $filtered; 834 return $filtered;
835 } 835 }
836 836
837 // Filter by day. Day must be in the form 'YYYYMMDD' (eg. '20120125') 837 // Filter by day. Day must be in the form 'YYYYMMDD' (e.g. '20120125')
838 // Sort order is: older articles first. 838 // Sort order is: older articles first.
839 // eg. print_r($mydb->filterDay('20120125')); 839 // e.g. print_r($mydb->filterDay('20120125'));
840 public function filterDay($day) 840 public function filterDay($day)
841 { 841 {
842 $filtered=array(); 842 $filtered=array();
@@ -891,13 +891,13 @@ class linkdb implements Iterator, Countable, ArrayAccess
891} 891}
892 892
893// ------------------------------------------------------------------------------------------ 893// ------------------------------------------------------------------------------------------
894// Ouput the last N links in RSS 2.0 format. 894// Output the last N links in RSS 2.0 format.
895function showRSS() 895function showRSS()
896{ 896{
897 header('Content-Type: application/rss+xml; charset=utf-8'); 897 header('Content-Type: application/rss+xml; charset=utf-8');
898 898
899 // $usepermalink : If true, use permalink instead of final link. 899 // $usepermalink : If true, use permalink instead of final link.
900 // User just has to add 'permalink' in URL parameters. eg. http://mysite.com/shaarli/?do=rss&permalinks 900 // User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=rss&permalinks
901 $usepermalinks = isset($_GET['permalinks']); 901 $usepermalinks = isset($_GET['permalinks']);
902 902
903 // Cache system 903 // Cache system
@@ -906,9 +906,9 @@ function showRSS()
906 $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } 906 $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
907 907
908 // If cached was not found (or not usable), then read the database and build the response: 908 // If cached was not found (or not usable), then read the database and build the response:
909 $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). 909 $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if user it not logged in).
910 910
911 // Optionnaly filter the results: 911 // Optionally filter the results:
912 $linksToDisplay=array(); 912 $linksToDisplay=array();
913 if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); 913 if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
914 elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); 914 elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
@@ -965,13 +965,13 @@ function showRSS()
965} 965}
966 966
967// ------------------------------------------------------------------------------------------ 967// ------------------------------------------------------------------------------------------
968// Ouput the last N links in ATOM format. 968// Output the last N links in ATOM format.
969function showATOM() 969function showATOM()
970{ 970{
971 header('Content-Type: application/atom+xml; charset=utf-8'); 971 header('Content-Type: application/atom+xml; charset=utf-8');
972 972
973 // $usepermalink : If true, use permalink instead of final link. 973 // $usepermalink : If true, use permalink instead of final link.
974 // User just has to add 'permalink' in URL parameters. eg. http://mysite.com/shaarli/?do=atom&permalinks 974 // User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=atom&permalinks
975 $usepermalinks = isset($_GET['permalinks']); 975 $usepermalinks = isset($_GET['permalinks']);
976 976
977 // Cache system 977 // Cache system
@@ -983,7 +983,7 @@ function showATOM()
983 $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). 983 $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
984 984
985 985
986 // Optionnaly filter the results: 986 // Optionally filter the results:
987 $linksToDisplay=array(); 987 $linksToDisplay=array();
988 if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); 988 if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
989 elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); 989 elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
@@ -1079,7 +1079,7 @@ function showDailyRSS()
1079 if (empty($days[$day])) $days[$day]=array(); 1079 if (empty($days[$day])) $days[$day]=array();
1080 $days[$day][]=$linkdate; 1080 $days[$day][]=$linkdate;
1081 } 1081 }
1082 if (count($days)>$nb_of_days) break; // Have we collected enough days ? 1082 if (count($days)>$nb_of_days) break; // Have we collected enough days?
1083 } 1083 }
1084 1084
1085 // Build the RSS feed. 1085 // Build the RSS feed.
@@ -1158,7 +1158,7 @@ function showDaily()
1158 } 1158 }
1159 1159
1160 /* We need to spread the articles on 3 columns. 1160 /* We need to spread the articles on 3 columns.
1161 I did not want to use a javascript lib like http://masonry.desandro.com/ 1161 I did not want to use a JavaScript lib like http://masonry.desandro.com/
1162 so I manually spread entries with a simple method: I roughly evaluate the 1162 so I manually spread entries with a simple method: I roughly evaluate the
1163 height of a div according to title and description length. 1163 height of a div according to title and description length.
1164 */ 1164 */
@@ -1169,7 +1169,7 @@ function showDaily()
1169 // Roughly estimate length of entry (by counting characters) 1169 // Roughly estimate length of entry (by counting characters)
1170 // Title: 30 chars = 1 line. 1 line is 30 pixels height. 1170 // Title: 30 chars = 1 line. 1 line is 30 pixels height.
1171 // Description: 836 characters gives roughly 342 pixel height. 1171 // Description: 836 characters gives roughly 342 pixel height.
1172 // This is not perfect, but it's usually ok. 1172 // This is not perfect, but it's usually OK.
1173 $length=strlen($link['title'])+(342*strlen($link['description']))/836; 1173 $length=strlen($link['title'])+(342*strlen($link['description']))/836;
1174 if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height. 1174 if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height.
1175 // Then put in column which is the less filled: 1175 // Then put in column which is the less filled:
@@ -1222,7 +1222,7 @@ function renderPage()
1222 // -------- Picture wall 1222 // -------- Picture wall
1223 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=picwall')) 1223 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=picwall'))
1224 { 1224 {
1225 // Optionnaly filter the results: 1225 // Optionally filter the results:
1226 $links=array(); 1226 $links=array();
1227 if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); 1227 if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']);
1228 elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); 1228 elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags']));
@@ -1302,7 +1302,7 @@ function renderPage()
1302 if (isset($_GET['linksperpage'])) 1302 if (isset($_GET['linksperpage']))
1303 { 1303 {
1304 if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); } 1304 if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); }
1305 // Make sure the referer is from Shaarli itself. 1305 // Make sure the referrer is Shaarli itself.
1306 $referer = '?'; 1306 $referer = '?';
1307 if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) 1307 if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0)
1308 $referer = $_SERVER['HTTP_REFERER']; 1308 $referer = $_SERVER['HTTP_REFERER'];
@@ -1321,7 +1321,7 @@ function renderPage()
1321 { 1321 {
1322 unset($_SESSION['privateonly']); // See all links 1322 unset($_SESSION['privateonly']); // See all links
1323 } 1323 }
1324 // Make sure the referer is from Shaarli itself. 1324 // Make sure the referrer is Shaarli itself.
1325 $referer = '?'; 1325 $referer = '?';
1326 if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) 1326 if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0)
1327 $referer = $_SERVER['HTTP_REFERER']; 1327 $referer = $_SERVER['HTTP_REFERER'];
@@ -1332,7 +1332,7 @@ function renderPage()
1332 // -------- Handle other actions allowed for non-logged in users: 1332 // -------- Handle other actions allowed for non-logged in users:
1333 if (!isLoggedIn()) 1333 if (!isLoggedIn())
1334 { 1334 {
1335 // User tries to post new link but is not loggedin: 1335 // User tries to post new link but is not logged in:
1336 // Show login screen, then redirect to ?post=... 1336 // Show login screen, then redirect to ?post=...
1337 if (isset($_GET['post'])) 1337 if (isset($_GET['post']))
1338 { 1338 {
@@ -1342,7 +1342,7 @@ function renderPage()
1342 $PAGE = new pageBuilder; 1342 $PAGE = new pageBuilder;
1343 buildLinkList($PAGE,$LINKSDB); // Compute list of links to display 1343 buildLinkList($PAGE,$LINKSDB); // Compute list of links to display
1344 $PAGE->renderPage('linklist'); 1344 $PAGE->renderPage('linklist');
1345 exit; // Never remove this one ! All operations below are reserved for logged in user. 1345 exit; // Never remove this one! All operations below are reserved for logged in user.
1346 } 1346 }
1347 1347
1348 // -------- All other functions are reserved for the registered user: 1348 // -------- All other functions are reserved for the registered user:
@@ -1363,7 +1363,7 @@ function renderPage()
1363 if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.'); 1363 if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.');
1364 if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) 1364 if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword']))
1365 { 1365 {
1366 if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! 1366 if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away!
1367 1367
1368 // Make sure old password is correct. 1368 // Make sure old password is correct.
1369 $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']); 1369 $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']);
@@ -1390,7 +1390,7 @@ function renderPage()
1390 { 1390 {
1391 if (!empty($_POST['title']) ) 1391 if (!empty($_POST['title']) )
1392 { 1392 {
1393 if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! 1393 if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away!
1394 $tz = 'UTC'; 1394 $tz = 'UTC';
1395 if (!empty($_POST['continent']) && !empty($_POST['city'])) 1395 if (!empty($_POST['continent']) && !empty($_POST['city']))
1396 if (isTZvalid($_POST['continent'],$_POST['city'])) 1396 if (isTZvalid($_POST['continent'],$_POST['city']))
@@ -1414,7 +1414,7 @@ function renderPage()
1414 $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); 1414 $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES));
1415 $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); 1415 $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES));
1416 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); 1416 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
1417 $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ? 1417 $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template?
1418 $PAGE->assign('timezone_js',$timezone_js); 1418 $PAGE->assign('timezone_js',$timezone_js);
1419 $PAGE->renderPage('configure'); 1419 $PAGE->renderPage('configure');
1420 exit; 1420 exit;
@@ -1438,7 +1438,7 @@ function renderPage()
1438 if (!empty($_POST['deletetag']) && !empty($_POST['fromtag'])) 1438 if (!empty($_POST['deletetag']) && !empty($_POST['fromtag']))
1439 { 1439 {
1440 $needle=trim($_POST['fromtag']); 1440 $needle=trim($_POST['fromtag']);
1441 $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. 1441 $linksToAlter = $LINKSDB->filterTags($needle,true); // True for case-sensitive tag search.
1442 foreach($linksToAlter as $key=>$value) 1442 foreach($linksToAlter as $key=>$value)
1443 { 1443 {
1444 $tags = explode(' ',trim($value['tags'])); 1444 $tags = explode(' ',trim($value['tags']));
@@ -1446,7 +1446,7 @@ function renderPage()
1446 $value['tags']=trim(implode(' ',$tags)); 1446 $value['tags']=trim(implode(' ',$tags));
1447 $LINKSDB[$key]=$value; 1447 $LINKSDB[$key]=$value;
1448 } 1448 }
1449 $LINKSDB->savedb(); // save to disk 1449 $LINKSDB->savedb(); // Save to disk.
1450 echo '<script language="JavaScript">alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>'; 1450 echo '<script language="JavaScript">alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>';
1451 exit; 1451 exit;
1452 } 1452 }
@@ -1459,17 +1459,17 @@ function renderPage()
1459 foreach($linksToAlter as $key=>$value) 1459 foreach($linksToAlter as $key=>$value)
1460 { 1460 {
1461 $tags = explode(' ',trim($value['tags'])); 1461 $tags = explode(' ',trim($value['tags']));
1462 $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Remplace tags value. 1462 $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Replace tags value.
1463 $value['tags']=trim(implode(' ',$tags)); 1463 $value['tags']=trim(implode(' ',$tags));
1464 $LINKSDB[$key]=$value; 1464 $LINKSDB[$key]=$value;
1465 } 1465 }
1466 $LINKSDB->savedb(); // save to disk 1466 $LINKSDB->savedb(); // Save to disk.
1467 echo '<script language="JavaScript">alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>'; 1467 echo '<script language="JavaScript">alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>';
1468 exit; 1468 exit;
1469 } 1469 }
1470 } 1470 }
1471 1471
1472 // -------- User wants to add a link without using the bookmarklet: show form. 1472 // -------- User wants to add a link without using the bookmarklet: Show form.
1473 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink')) 1473 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink'))
1474 { 1474 {
1475 $PAGE = new pageBuilder; 1475 $PAGE = new pageBuilder;
@@ -1481,7 +1481,7 @@ function renderPage()
1481 // -------- User clicked the "Save" button when editing a link: Save link to database. 1481 // -------- User clicked the "Save" button when editing a link: Save link to database.
1482 if (isset($_POST['save_edit'])) 1482 if (isset($_POST['save_edit']))
1483 { 1483 {
1484 if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! 1484 if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away!
1485 $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. 1485 $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces.
1486 $linkdate=$_POST['lf_linkdate']; 1486 $linkdate=$_POST['lf_linkdate'];
1487 $url = trim($_POST['lf_url']); 1487 $url = trim($_POST['lf_url']);
@@ -1491,7 +1491,7 @@ function renderPage()
1491 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags)); 1491 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags));
1492 if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. 1492 if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title.
1493 $LINKSDB[$linkdate] = $link; 1493 $LINKSDB[$linkdate] = $link;
1494 $LINKSDB->savedb(); // save to disk 1494 $LINKSDB->savedb(); // Save to disk.
1495 pubsubhub(); 1495 pubsubhub();
1496 1496
1497 // If we are called from the bookmarklet, we must close the popup: 1497 // If we are called from the bookmarklet, we must close the popup:
@@ -1505,7 +1505,7 @@ function renderPage()
1505 // -------- User clicked the "Cancel" button when editing a link. 1505 // -------- User clicked the "Cancel" button when editing a link.
1506 if (isset($_POST['cancel_edit'])) 1506 if (isset($_POST['cancel_edit']))
1507 { 1507 {
1508 // If we are called from the bookmarklet, we must close the popup; 1508 // If we are called from the bookmarklet, we must close the popup:
1509 if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo '<script language="JavaScript">self.close();</script>'; exit; } 1509 if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo '<script language="JavaScript">self.close();</script>'; exit; }
1510 $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); 1510 $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
1511 $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. 1511 $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
@@ -1513,12 +1513,12 @@ function renderPage()
1513 exit; 1513 exit;
1514 } 1514 }
1515 1515
1516 // -------- User clicked the "Delete" button when editing a link : Delete link from database. 1516 // -------- User clicked the "Delete" button when editing a link: Delete link from database.
1517 if (isset($_POST['delete_link'])) 1517 if (isset($_POST['delete_link']))
1518 { 1518 {
1519 if (!tokenOk($_POST['token'])) die('Wrong token.'); 1519 if (!tokenOk($_POST['token'])) die('Wrong token.');
1520 // We do not need to ask for confirmation: 1520 // We do not need to ask for confirmation:
1521 // - confirmation is handled by javascript 1521 // - confirmation is handled by JavaScript
1522 // - we are protected from XSRF by the token. 1522 // - we are protected from XSRF by the token.
1523 $linkdate=$_POST['lf_linkdate']; 1523 $linkdate=$_POST['lf_linkdate'];
1524 unset($LINKSDB[$linkdate]); 1524 unset($LINKSDB[$linkdate]);
@@ -1568,7 +1568,7 @@ function renderPage()
1568 $tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL 1568 $tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL
1569 $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL 1569 $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL
1570 if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url; 1570 if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url;
1571 // 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.) 1571 // If this is an HTTP link, we try go get the page to extract the title (otherwise we will to straight to the edit form.)
1572 if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http') 1572 if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http')
1573 { 1573 {
1574 list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive. 1574 list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive.
@@ -1622,7 +1622,7 @@ function renderPage()
1622 exit; 1622 exit;
1623 } 1623 }
1624 $exportWhat=$_GET['what']; 1624 $exportWhat=$_GET['what'];
1625 if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???'); 1625 if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export???');
1626 1626
1627 header('Content-Type: text/html; charset=utf-8'); 1627 header('Content-Type: text/html; charset=utf-8');
1628 header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html'); 1628 header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html');
@@ -1695,8 +1695,8 @@ function importFile()
1695 $filename=$_FILES['filetoupload']['name']; 1695 $filename=$_FILES['filetoupload']['name'];
1696 $filesize=$_FILES['filetoupload']['size']; 1696 $filesize=$_FILES['filetoupload']['size'];
1697 $data=file_get_contents($_FILES['filetoupload']['tmp_name']); 1697 $data=file_get_contents($_FILES['filetoupload']['tmp_name']);
1698 $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private ? 1698 $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private?
1699 $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones ? 1699 $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones?
1700 $import_count=0; 1700 $import_count=0;
1701 1701
1702 // Sniff file type: 1702 // Sniff file type:
@@ -1707,7 +1707,7 @@ function importFile()
1707 if ($type=='netscape') 1707 if ($type=='netscape')
1708 { 1708 {
1709 // This is a standard Netscape-style bookmark file. 1709 // This is a standard Netscape-style bookmark file.
1710 // This format is supported by all browsers (except IE, of course), also delicious, diigo and others. 1710 // This format is supported by all browsers (except IE, of course), also Delicious, Diigo and others.
1711 foreach(explode('<DT>',$data) as $html) // explode is very fast 1711 foreach(explode('<DT>',$data) as $html) // explode is very fast
1712 { 1712 {
1713 $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); 1713 $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0);
@@ -1741,14 +1741,14 @@ function importFile()
1741 1741
1742 // Make sure date/time is not already used by another link. 1742 // Make sure date/time is not already used by another link.
1743 // (Some bookmark files have several different links with the same ADD_DATE) 1743 // (Some bookmark files have several different links with the same ADD_DATE)
1744 // We increment date by 1 second until we find a date which is not used in db. 1744 // We increment date by 1 second until we find a date which is not used in DB.
1745 // (so that links that have the same date/time are more or less kept grouped by date, but do not conflict.) 1745 // (so that links that have the same date/time are more or less kept grouped by date, but do not conflict.)
1746 while (!empty($LINKSDB[date('Ymd_His',$raw_add_date)])) { $raw_add_date++; }// Yes, I know it's ugly. 1746 while (!empty($LINKSDB[date('Ymd_His',$raw_add_date)])) { $raw_add_date++; }// Yes, I know it's ugly.
1747 $link['linkdate']=date('Ymd_His',$raw_add_date); 1747 $link['linkdate']=date('Ymd_His',$raw_add_date);
1748 $LINKSDB[$link['linkdate']] = $link; 1748 $LINKSDB[$link['linkdate']] = $link;
1749 $import_count++; 1749 $import_count++;
1750 } 1750 }
1751 else // link already present in database. 1751 else // Link already present in database.
1752 { 1752 {
1753 if ($overwrite) 1753 if ($overwrite)
1754 { // If overwrite is required, we import link data, except date/time. 1754 { // If overwrite is required, we import link data, except date/time.
@@ -1799,13 +1799,13 @@ function buildLinkList($PAGE,$LINKSDB)
1799 { 1799 {
1800 header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); 1800 header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
1801 echo '<h1>404 Not found.</h1>Oh crap. The link you are trying to reach does not exist or has been deleted.'; 1801 echo '<h1>404 Not found.</h1>Oh crap. The link you are trying to reach does not exist or has been deleted.';
1802 echo '<br>You would mind <a href="?">clicking here</a> ?'; 1802 echo '<br>You would mind <a href="?">clicking here</a>?';
1803 exit; 1803 exit;
1804 } 1804 }
1805 $search_type='permalink'; 1805 $search_type='permalink';
1806 } 1806 }
1807 else 1807 else
1808 $linksToDisplay = $LINKSDB; // otherwise, display without filtering. 1808 $linksToDisplay = $LINKSDB; // Otherwise, display without filtering.
1809 1809
1810 // Option: Show only private links 1810 // Option: Show only private links
1811 if (!empty($_SESSION['privateonly'])) 1811 if (!empty($_SESSION['privateonly']))
@@ -1819,11 +1819,11 @@ function buildLinkList($PAGE,$LINKSDB)
1819 } 1819 }
1820 1820
1821 // ---- Handle paging. 1821 // ---- Handle paging.
1822 /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess ??? 1822 /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess???
1823 "Warning: array_keys() expects parameter 1 to be array, object given in ... " 1823 "Warning: array_keys() expects parameter 1 to be array, object given in ... "
1824 If my class implements ArrayAccess, why won't array_keys() accept it ? ( $keys=array_keys($linksToDisplay); ) 1824 If my class implements ArrayAccess, why won't array_keys() accept it ? ( $keys=array_keys($linksToDisplay); )
1825 */ 1825 */
1826 $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks php. 1826 $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks PHP.
1827 1827
1828 // If there is only a single link, we change on-the-fly the title of the page. 1828 // If there is only a single link, we change on-the-fly the title of the page.
1829 if (count($linksToDisplay)==1) $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; 1829 if (count($linksToDisplay)==1) $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title'];
@@ -1870,7 +1870,7 @@ function buildLinkList($PAGE,$LINKSDB)
1870 $PAGE->assign('result_count',count($linksToDisplay)); 1870 $PAGE->assign('result_count',count($linksToDisplay));
1871 $PAGE->assign('search_type',$search_type); 1871 $PAGE->assign('search_type',$search_type);
1872 $PAGE->assign('search_crits',$search_crits); 1872 $PAGE->assign('search_crits',$search_crits);
1873 $PAGE->assign('redirector',empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']); // optional redirector URL 1873 $PAGE->assign('redirector',empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']); // Optional redirector URL.
1874 $PAGE->assign('token',$token); 1874 $PAGE->assign('token',$token);
1875 $PAGE->assign('links',$linkDisp); 1875 $PAGE->assign('links',$linkDisp);
1876 return; 1876 return;
@@ -1878,9 +1878,9 @@ function buildLinkList($PAGE,$LINKSDB)
1878 1878
1879// Compute the thumbnail for a link. 1879// Compute the thumbnail for a link.
1880// 1880//
1881// with a link to the original URL. 1881// With a link to the original URL.
1882// Understands various services (youtube.com...) 1882// Understands various services (youtube.com...)
1883// Input: $url = url for which the thumbnail must be found. 1883// Input: $url = URL for which the thumbnail must be found.
1884// $href = if provided, this URL will be followed instead of $url 1884// $href = if provided, this URL will be followed instead of $url
1885// Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) 1885// Returns an associative array with thumbnail attributes (src,href,width,height,style,alt)
1886// Some of them may be missing. 1886// Some of them may be missing.
@@ -1891,7 +1891,7 @@ function computeThumbnail($url,$href=false)
1891 if ($href==false) $href=$url; 1891 if ($href==false) $href=$url;
1892 1892
1893 // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. 1893 // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link.
1894 // (eg. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg ) 1894 // (e.g. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg )
1895 // ^^^^^^^^^^^ ^^^^^^^^^^^ 1895 // ^^^^^^^^^^^ ^^^^^^^^^^^
1896 $domain = parse_url($url,PHP_URL_HOST); 1896 $domain = parse_url($url,PHP_URL_HOST);
1897 if ($domain=='youtube.com' || $domain=='www.youtube.com') 1897 if ($domain=='youtube.com' || $domain=='www.youtube.com')
@@ -1964,17 +1964,17 @@ function computeThumbnail($url,$href=false)
1964 ) 1964 )
1965 { 1965 {
1966 if ($domain=='vimeo.com') 1966 if ($domain=='vimeo.com')
1967 { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric) 1967 { // Make sure this vimeo URL points to a video (/xxx... where xxx is numeric)
1968 $path = parse_url($url,PHP_URL_PATH); 1968 $path = parse_url($url,PHP_URL_PATH);
1969 if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL. 1969 if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL.
1970 } 1970 }
1971 if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) 1971 if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com'))
1972 { // Make sure this url points to a single comic (/xxx... where xxx is numeric) 1972 { // Make sure this URL points to a single comic (/xxx... where xxx is numeric)
1973 $path = parse_url($url,PHP_URL_PATH); 1973 $path = parse_url($url,PHP_URL_PATH);
1974 if (!preg_match('!/\d+.+?!',$path)) return array(); 1974 if (!preg_match('!/\d+.+?!',$path)) return array();
1975 } 1975 }
1976 if ($domain=='ted.com' || endsWith($domain,'.ted.com')) 1976 if ($domain=='ted.com' || endsWith($domain,'.ted.com'))
1977 { // Make sure this TED url points to a video (/talks/...) 1977 { // Make sure this TED URL points to a video (/talks/...)
1978 $path = parse_url($url,PHP_URL_PATH); 1978 $path = parse_url($url,PHP_URL_PATH);
1979 if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. 1979 if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL.
1980 } 1980 }
@@ -2001,7 +2001,7 @@ function computeThumbnail($url,$href=false)
2001// Returns the HTML code to display a thumbnail for a link 2001// Returns the HTML code to display a thumbnail for a link
2002// with a link to the original URL. 2002// with a link to the original URL.
2003// Understands various services (youtube.com...) 2003// Understands various services (youtube.com...)
2004// Input: $url = url for which the thumbnail must be found. 2004// Input: $url = URL for which the thumbnail must be found.
2005// $href = if provided, this URL will be followed instead of $url 2005// $href = if provided, this URL will be followed instead of $url
2006// Returns '' if no thumbnail available. 2006// Returns '' if no thumbnail available.
2007function thumbnail($url,$href=false) 2007function thumbnail($url,$href=false)
@@ -2022,7 +2022,7 @@ function thumbnail($url,$href=false)
2022// Returns the HTML code to display a thumbnail for a link 2022// Returns the HTML code to display a thumbnail for a link
2023// for the picture wall (using lazy image loading) 2023// for the picture wall (using lazy image loading)
2024// Understands various services (youtube.com...) 2024// Understands various services (youtube.com...)
2025// Input: $url = url for which the thumbnail must be found. 2025// Input: $url = URL for which the thumbnail must be found.
2026// $href = if provided, this URL will be followed instead of $url 2026// $href = if provided, this URL will be followed instead of $url
2027// Returns '' if no thumbnail available. 2027// Returns '' if no thumbnail available.
2028function lazyThumbnail($url,$href=false) 2028function lazyThumbnail($url,$href=false)
@@ -2032,7 +2032,7 @@ function lazyThumbnail($url,$href=false)
2032 2032
2033 $html='<a href="'.htmlspecialchars($t['href']).'">'; 2033 $html='<a href="'.htmlspecialchars($t['href']).'">';
2034 2034
2035 // Lazy image (only loaded by javascript when in the viewport). 2035 // Lazy image (only loaded by JavaScript when in the viewport).
2036 if (!empty($GLOBALS['disablejquery'])) // (except if jQuery is disabled) 2036 if (!empty($GLOBALS['disablejquery'])) // (except if jQuery is disabled)
2037 $html.='<img class="lazyimage" src="'.htmlspecialchars($t['src']).'"'; 2037 $html.='<img class="lazyimage" src="'.htmlspecialchars($t['src']).'"';
2038 else 2038 else
@@ -2044,7 +2044,7 @@ function lazyThumbnail($url,$href=false)
2044 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; 2044 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"';
2045 $html.='>'; 2045 $html.='>';
2046 2046
2047 // No-javascript fallback. 2047 // No-JavaScript fallback.
2048 $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"'; 2048 $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"';
2049 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; 2049 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
2050 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; 2050 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
@@ -2081,7 +2081,7 @@ function install()
2081 header('Location: '.indexUrl().'?test_session'); // Redirect to check stored data. 2081 header('Location: '.indexUrl().'?test_session'); // Redirect to check stored data.
2082 } 2082 }
2083 if (isset($_GET['test_session'])) 2083 if (isset($_GET['test_session']))
2084 { // Step 3: Sessions are ok. Remove test parameter from URL. 2084 { // Step 3: Sessions are OK. Remove test parameter from URL.
2085 header('Location: '.indexUrl()); 2085 header('Location: '.indexUrl());
2086 } 2086 }
2087 2087
@@ -2099,7 +2099,7 @@ function install()
2099 $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); 2099 $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
2100 $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] ); 2100 $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] );
2101 writeConfig(); 2101 writeConfig();
2102 echo '<script language="JavaScript">alert("Shaarli is now configured. Please enter your login/password and start shaaring your links !");document.location=\'?do=login\';</script>'; 2102 echo '<script language="JavaScript">alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>';
2103 exit; 2103 exit;
2104 } 2104 }
2105 2105
@@ -2114,14 +2114,14 @@ function install()
2114 exit; 2114 exit;
2115} 2115}
2116 2116
2117// Generates the timezone selection form and javascript. 2117// Generates the timezone selection form and JavaScript.
2118// Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected. 2118// Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected.
2119// Output: array(html,js) 2119// Output: array(html,js)
2120// Example: list($htmlform,$js) = templateTZform('Europe/Paris'); // Europe/Paris pre-selected. 2120// Example: list($htmlform,$js) = templateTZform('Europe/Paris'); // Europe/Paris pre-selected.
2121// Returns array('','') if server does not support timezones list. (eg. php 5.1 on free.fr) 2121// Returns array('','') if server does not support timezones list. (e.g. PHP 5.1 on free.fr)
2122function templateTZform($ptz=false) 2122function templateTZform($ptz=false)
2123{ 2123{
2124 if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr 2124 if (function_exists('timezone_identifiers_list')) // because of old PHP version (5.1) which can be found on free.fr
2125 { 2125 {
2126 // Try to split the provided timezone. 2126 // Try to split the provided timezone.
2127 if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; } 2127 if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; }
@@ -2130,7 +2130,7 @@ function templateTZform($ptz=false)
2130 // Display config form: 2130 // Display config form:
2131 $timezone_form = ''; 2131 $timezone_form = '';
2132 $timezone_js = ''; 2132 $timezone_js = '';
2133 // The list is in the forme "Europe/Paris", "America/Argentina/Buenos_Aires"... 2133 // The list is in the form "Europe/Paris", "America/Argentina/Buenos_Aires"...
2134 // We split the list in continents/cities. 2134 // We split the list in continents/cities.
2135 $continents = array(); 2135 $continents = array();
2136 $cities = array(); 2136 $cities = array();
@@ -2168,9 +2168,9 @@ function templateTZform($ptz=false)
2168function isTZvalid($continent,$city) 2168function isTZvalid($continent,$city)
2169{ 2169{
2170 $tz = $continent.'/'.$city; 2170 $tz = $continent.'/'.$city;
2171 if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr 2171 if (function_exists('timezone_identifiers_list')) // because of old PHP version (5.1) which can be found on free.fr
2172 { 2172 {
2173 if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone ? 2173 if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone?
2174 return true; 2174 return true;
2175 } 2175 }
2176 return false; 2176 return false;
@@ -2213,7 +2213,7 @@ if (!function_exists('json_encode')) {
2213} 2213}
2214 2214
2215// Webservices (for use with jQuery/jQueryUI) 2215// Webservices (for use with jQuery/jQueryUI)
2216// eg. index.php?ws=tags&term=minecr 2216// e.g. index.php?ws=tags&term=minecr
2217function processWS() 2217function processWS()
2218{ 2218{
2219 if (empty($_GET['ws']) || empty($_GET['term'])) return; 2219 if (empty($_GET['ws']) || empty($_GET['term'])) return;
@@ -2221,7 +2221,7 @@ function processWS()
2221 $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). 2221 $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
2222 header('Content-Type: application/json; charset=utf-8'); 2222 header('Content-Type: application/json; charset=utf-8');
2223 2223
2224 // Search in tags (case insentitive, cumulative search) 2224 // Search in tags (case insensitive, cumulative search)
2225 if ($_GET['ws']=='tags') 2225 if ($_GET['ws']=='tags')
2226 { 2226 {
2227 $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") 2227 $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d")
@@ -2237,7 +2237,7 @@ function processWS()
2237 exit; 2237 exit;
2238 } 2238 }
2239 2239
2240 // Search a single tag (case sentitive, single tag search) 2240 // Search a single tag (case sensitive, single tag search)
2241 if ($_GET['ws']=='singletag') 2241 if ($_GET['ws']=='singletag')
2242 { 2242 {
2243 /* To speed up things, we store list of tags in session */ 2243 /* To speed up things, we store list of tags in session */
@@ -2253,7 +2253,7 @@ function processWS()
2253 2253
2254// Re-write configuration file according to globals. 2254// Re-write configuration file according to globals.
2255// Requires some $GLOBALS to be set (login,hash,salt,title). 2255// Requires some $GLOBALS to be set (login,hash,salt,title).
2256// If the config file cannot be saved, an error message is dislayed and the user is redirected to "Tools" menu. 2256// If the config file cannot be saved, an error message is displayed and the user is redirected to "Tools" menu.
2257// (otherwise, the function simply returns.) 2257// (otherwise, the function simply returns.)
2258function writeConfig() 2258function writeConfig()
2259{ 2259{
@@ -2273,12 +2273,12 @@ function writeConfig()
2273 } 2273 }
2274} 2274}
2275 2275
2276/* Because some f*cking services like Flickr require an extra HTTP request to get the thumbnail URL, 2276/* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL,
2277 I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. 2277 I have deported the thumbnail URL code generation here, otherwise this would slow down page generation.
2278 The following function takes the URL a link (eg. a flickr page) and return the proper thumbnail. 2278 The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail.
2279 This function is called by passing the url: 2279 This function is called by passing the URL:
2280 http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] 2280 http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL]
2281 [URL] is the URL of the link (eg. a flickr page) 2281 [URL] is the URL of the link (e.g. a flickr page)
2282 [HMAC] is the signature for the [URL] (so that these URL cannot be forged). 2282 [HMAC] is the signature for the [URL] (so that these URL cannot be forged).
2283 The function below will fetch the image from the webservice and store it in the cache. 2283 The function below will fetch the image from the webservice and store it in the cache.
2284*/ 2284*/
@@ -2286,7 +2286,7 @@ function genThumbnail()
2286{ 2286{
2287 // Make sure the parameters in the URL were generated by us. 2287 // Make sure the parameters in the URL were generated by us.
2288 $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']); 2288 $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']);
2289 if ($sign!=$_GET['hmac']) die('Naughty boy !'); 2289 if ($sign!=$_GET['hmac']) die('Naughty boy!');
2290 2290
2291 // Let's see if we don't already have the image for this URL in the cache. 2291 // Let's see if we don't already have the image for this URL in the cache.
2292 $thumbname=hash('sha1',$_GET['url']).'.jpg'; 2292 $thumbname=hash('sha1',$_GET['url']).'.jpg';
@@ -2311,22 +2311,22 @@ function genThumbnail()
2311 2311
2312 if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')) 2312 if ($domain=='flickr.com' || endsWith($domain,'.flickr.com'))
2313 { 2313 {
2314 // Crude replacement to handle new Flickr domain policy (They prefer www. now) 2314 // Crude replacement to handle new flickr domain policy (They prefer www. now)
2315 $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url); 2315 $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url);
2316 2316
2317 // Is this a link to an image, or to a flickr page ? 2317 // Is this a link to an image, or to a flickr page ?
2318 $imageurl=''; 2318 $imageurl='';
2319 if (endswith(parse_url($url,PHP_URL_PATH),'.jpg')) 2319 if (endswith(parse_url($url,PHP_URL_PATH),'.jpg'))
2320 { // This is a direct link to an image. eg. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg 2320 { // This is a direct link to an image. e.g. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg
2321 preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); 2321 preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches);
2322 if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; 2322 if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg';
2323 } 2323 }
2324 else // this is a flickr page (html) 2324 else // This is a flickr page (html)
2325 { 2325 {
2326 list($httpstatus,$headers,$data) = getHTTP($url,20); // Get the flickr html page. 2326 list($httpstatus,$headers,$data) = getHTTP($url,20); // Get the flickr html page.
2327 if (strpos($httpstatus,'200 OK')!==false) 2327 if (strpos($httpstatus,'200 OK')!==false)
2328 { 2328 {
2329 // Flickr now nicely provides the URL of the thumbnail in each flickr page. 2329 // flickr now nicely provides the URL of the thumbnail in each flickr page.
2330 preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!',$data,$matches); 2330 preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!',$data,$matches);
2331 if (!empty($matches[1])) $imageurl=$matches[1]; 2331 if (!empty($matches[1])) $imageurl=$matches[1];
2332 2332
@@ -2357,7 +2357,7 @@ function genThumbnail()
2357 elseif ($domain=='vimeo.com' ) 2357 elseif ($domain=='vimeo.com' )
2358 { 2358 {
2359 // This is more complex: we have to perform a HTTP request, then parse the result. 2359 // This is more complex: we have to perform a HTTP request, then parse the result.
2360 // Maybe we should deport this to javascript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098 2360 // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098
2361 $vid = substr(parse_url($url,PHP_URL_PATH),1); 2361 $vid = substr(parse_url($url,PHP_URL_PATH),1);
2362 list($httpstatus,$headers,$data) = getHTTP('http://vimeo.com/api/v2/video/'.htmlspecialchars($vid).'.php',5); 2362 list($httpstatus,$headers,$data) = getHTTP('http://vimeo.com/api/v2/video/'.htmlspecialchars($vid).'.php',5);
2363 if (strpos($httpstatus,'200 OK')!==false) 2363 if (strpos($httpstatus,'200 OK')!==false)
@@ -2493,7 +2493,7 @@ function resizeImage($filepath)
2493} 2493}
2494 2494
2495// Invalidate caches when the database is changed or the user logs out. 2495// Invalidate caches when the database is changed or the user logs out.
2496// (eg. tags cache). 2496// (e.g. tags cache).
2497function invalidateCaches() 2497function invalidateCaches()
2498{ 2498{
2499 unset($_SESSION['tags']); // Purge cache attached to session. 2499 unset($_SESSION['tags']); // Purge cache attached to session.
diff --git a/tpl/configure.html b/tpl/configure.html
index ef20e94e..645107ae 100644
--- a/tpl/configure.html
+++ b/tpl/configure.html
@@ -19,7 +19,7 @@
19 <tr><td valign="top"><b>Security:</b></td><td><input type="checkbox" name="disablesessionprotection" id="disablesessionprotection" {if="!empty($GLOBALS['disablesessionprotection'])"}checked{/if}><label for="disablesessionprotection">&nbsp;Disable session cookie hijacking protection (Check this if you get disconnected often or if your IP address changes often.)</label></td></tr> 19 <tr><td valign="top"><b>Security:</b></td><td><input type="checkbox" name="disablesessionprotection" id="disablesessionprotection" {if="!empty($GLOBALS['disablesessionprotection'])"}checked{/if}><label for="disablesessionprotection">&nbsp;Disable session cookie hijacking protection (Check this if you get disconnected often or if your IP address changes often.)</label></td></tr>
20 20
21 <tr><td valign="top"><b>Features:</b></td><td> 21 <tr><td valign="top"><b>Features:</b></td><td>
22 <input type="checkbox" name="disablejquery" id="disablejquery" {if="!empty($GLOBALS['disablejquery'])"}checked{/if}><label for="disablejquery">&nbsp;Disable jQuery and all heavy javascript (for example: Autocomplete in tags. Useful for slow computers.)</label> 22 <input type="checkbox" name="disablejquery" id="disablejquery" {if="!empty($GLOBALS['disablejquery'])"}checked{/if}><label for="disablejquery">&nbsp;Disable jQuery and all heavy JavaScript (for example: Autocomplete in tags. Useful for slow computers.)</label>
23 </td></tr> 23 </td></tr>
24 <tr><td valign="top"><b>New link:</b></td><td> 24 <tr><td valign="top"><b>New link:</b></td><td>
25 <input type="checkbox" name="privateLinkByDefault" id="privateLinkByDefault" {if="!empty($GLOBALS['privateLinkByDefault'])"}checked{/if}/><label for="privateLinkByDefault">&nbsp;All new link are private by default</label></td> 25 <input type="checkbox" name="privateLinkByDefault" id="privateLinkByDefault" {if="!empty($GLOBALS['privateLinkByDefault'])"}checked{/if}/><label for="privateLinkByDefault">&nbsp;All new link are private by default</label></td>
@@ -30,4 +30,4 @@
30</div> 30</div>
31{include="page.footer"} 31{include="page.footer"}
32</body> 32</body>
33</html> 33</html> \ No newline at end of file
diff --git a/tpl/import.html b/tpl/import.html
index 9e581fc9..259e56ee 100644
--- a/tpl/import.html
+++ b/tpl/import.html
@@ -5,7 +5,7 @@
5<div id="pageheader"> 5<div id="pageheader">
6 {include="page.header"} 6 {include="page.header"}
7 <div id="uploaddiv"> 7 <div id="uploaddiv">
8 Import Netscape html bookmarks (as exported from Firefox/Chrome/Opera/delicious/diigo...) (Max: {$maxfilesize|htmlspecialchars} bytes). 8 Import Netscape HTML bookmarks (as exported from Firefox/Chrome/Opera/Delicious/Diigo...) (Max: {$maxfilesize|htmlspecialchars} bytes).
9 <form method="POST" action="?do=upload" enctype="multipart/form-data" name="uploadform" id="uploadform"> 9 <form method="POST" action="?do=upload" enctype="multipart/form-data" name="uploadform" id="uploadform">
10 <input type="hidden" name="token" value="{$token}"> 10 <input type="hidden" name="token" value="{$token}">
11 <input type="file" name="filetoupload" size="80"> 11 <input type="file" name="filetoupload" size="80">