diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 254 |
1 files changed, 127 insertions, 127 deletions
@@ -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. |
35 | if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); | 35 | if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); |
36 | 36 | ||
37 | define('shaarli_version','0.0.42 beta'); | 37 | define('shaarli_version','0.0.42 beta'); |
38 | define('PHPPREFIX','<?php /* '); // Prefix to encapsulate data in php code. | 38 | define('PHPPREFIX','<?php /* '); // Prefix to encapsulate data in PHP code. |
39 | define('PHPSUFFIX',' */ ?>'); // Suffix to encapsulate data in php code. | 39 | define('PHPSUFFIX',' */ ?>'); // Suffix to encapsulate data in PHP code. |
40 | // http://server.com/x/shaarli --> /shaarli/ | 40 | // http://server.com/x/shaarli --> /shaarli/ |
41 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 41 | define('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. |
49 | define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired. | 49 | define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired. |
50 | ini_set('session.use_cookies', 1); // Use cookies to store session. | 50 | ini_set('session.use_cookies', 1); // Use cookies to store session. |
51 | ini_set('session.use_only_cookies', 1); // Force cookies for session (phpsessionID forbidden in URL) | 51 | ini_set('session.use_only_cookies', 1); // Force cookies for session (phpsessionID forbidden in URL). |
52 | ini_set('session.use_trans_sid', false); // Prevent php to use sessionID in URL if cookies are disabled. | 52 | ini_set('session.use_trans_sid', false); // Prevent PHP form using sessionID in URL if cookies are disabled. |
53 | session_name('shaarli'); | 53 | session_name('shaarli'); |
54 | if (session_id() == '') session_start(); // Start session if needed (Some server auto-start sessions). | 54 | if (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"); | |||
85 | header("Cache-Control: post-check=0, pre-check=0", false); | 85 | header("Cache-Control: post-check=0, pre-check=0", false); |
86 | header("Pragma: no-cache"); | 86 | header("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.) |
89 | if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory ('.realpath(dirname(__FILE__)).').</pre>'); | 89 | if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory ('.realpath(dirname(__FILE__)).').</pre>'); |
90 | if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } | 90 | if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } |
91 | if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } // For RainTPL temporary files. | 91 | if (!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 | |||
119 | autoLocale(); // Sniff browser language and set date format accordingly. | 119 | autoLocale(); // Sniff browser language and set date format accordingly. |
120 | header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. | 120 | header('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 |
123 | function checkphpversion() | 123 | function 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() | |||
160 | class pageCache | 160 | class 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 |
246 | function text2clickable($url) | 246 | function text2clickable($url) |
247 | { | 247 | { |
@@ -262,8 +262,8 @@ function keepMultipleSpaces($text) | |||
262 | function autoLocale() | 262 | function 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 | ||
302 | function fillSessionInfo() { | 302 | function 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. |
452 | function serverUrl() | 452 | function 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/) |
461 | function indexUrl() | 461 | function 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) |
472 | function pageUrl() | 472 | function 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. |
478 | function return_bytes($val) | 478 | function 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) | |||
543 | function linkdate2locale($linkdate) | 543 | function 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. |
619 | function tokenOk($token) | 619 | function 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 | */ |
705 | class linkdb implements Iterator, Countable, ArrayAccess | 705 | class 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. |
895 | function showRSS() | 895 | function 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. |
969 | function showATOM() | 969 | function 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. |
2007 | function thumbnail($url,$href=false) | 2007 | function 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. |
2028 | function lazyThumbnail($url,$href=false) | 2028 | function 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) |
2122 | function templateTZform($ptz=false) | 2122 | function 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) | |||
2168 | function isTZvalid($continent,$city) | 2168 | function 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 |
2217 | function processWS() | 2217 | function 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.) |
2258 | function writeConfig() | 2258 | function 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). |
2497 | function invalidateCaches() | 2497 | function invalidateCaches() |
2498 | { | 2498 | { |
2499 | unset($_SESSION['tags']); // Purge cache attached to session. | 2499 | unset($_SESSION['tags']); // Purge cache attached to session. |