diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 272 |
1 files changed, 131 insertions, 141 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,21 @@ $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']['RAINTPL_TMP'] = 'tmp' ; // Raintpl cache directory | ||
30 | $GLOBALS['config']['RAINTPL_TPL'] = 'tpl/' ; // Raintpl template directory (keep the trailling slash!) | ||
29 | $GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli. | 31 | $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 | 32 | $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 | 33 | // Note: You must have publisher.php in the same directory as Shaarli index.php |
32 | // ----------------------------------------------------------------------------------------------- | 34 | // ----------------------------------------------------------------------------------------------- |
33 | // You should not touch below (or at your own risks !) | 35 | // You should not touch below (or at your own risks!) |
34 | // Optionnal config file. | 36 | // Optional config file. |
35 | if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); | 37 | if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); |
36 | 38 | ||
37 | define('shaarli_version','0.0.42 beta'); | 39 | define('shaarli_version','0.0.42 beta'); |
38 | define('PHPPREFIX','<?php /* '); // Prefix to encapsulate data in php code. | 40 | define('PHPPREFIX','<?php /* '); // Prefix to encapsulate data in PHP code. |
39 | define('PHPSUFFIX',' */ ?>'); // Suffix to encapsulate data in php code. | 41 | define('PHPSUFFIX',' */ ?>'); // Suffix to encapsulate data in PHP code. |
40 | // http://server.com/x/shaarli --> /shaarli/ | 42 | // http://server.com/x/shaarli --> /shaarli/ |
41 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 43 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); |
42 | 44 | ||
@@ -48,8 +50,8 @@ session_set_cookie_params($cookie['lifetime'],$cookiedir,$_SERVER['HTTP_HOST']); | |||
48 | // Set session parameters on server side. | 50 | // 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. | 51 | 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. | 52 | 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) | 53 | 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. | 54 | ini_set('session.use_trans_sid', false); // Prevent PHP form using sessionID in URL if cookies are disabled. |
53 | session_name('shaarli'); | 55 | session_name('shaarli'); |
54 | if (session_id() == '') session_start(); // Start session if needed (Some server auto-start sessions). | 56 | if (session_id() == '') session_start(); // Start session if needed (Some server auto-start sessions). |
55 | 57 | ||
@@ -63,9 +65,8 @@ error_reporting(E_ALL^E_WARNING); // See all error except warnings. | |||
63 | //error_reporting(-1); // See all errors (for debugging only) | 65 | //error_reporting(-1); // See all errors (for debugging only) |
64 | 66 | ||
65 | include "inc/rain.tpl.class.php"; //include Rain TPL | 67 | include "inc/rain.tpl.class.php"; //include Rain TPL |
66 | raintpl::$tpl_dir = "tpl/"; // template directory | 68 | raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory |
67 | if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } | 69 | raintpl::$cache_dir = $GLOBALS['config']['RAINTPL_TMP']; // cache directory |
68 | raintpl::$cache_dir = "tmp/"; // cache directory | ||
69 | 70 | ||
70 | ob_start(); // Output buffering for the page cache. | 71 | ob_start(); // Output buffering for the page cache. |
71 | 72 | ||
@@ -85,18 +86,8 @@ header("Cache-Control: no-store, no-cache, must-revalidate"); | |||
85 | header("Cache-Control: post-check=0, pre-check=0", false); | 86 | header("Cache-Control: post-check=0, pre-check=0", false); |
86 | header("Pragma: no-cache"); | 87 | header("Pragma: no-cache"); |
87 | 88 | ||
88 | // Directories creations (Note that your web host may require differents rights than 705.) | 89 | // 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>'); | 90 | 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); } | ||
91 | if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } // For RainTPL temporary files. | ||
92 | if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. | ||
93 | // Second check to see if Shaarli can write in its directory, because on some hosts is_writable() is not reliable. | ||
94 | if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) die('<pre>ERROR: Shaarli does not have the right to write in its data directory ('.realpath($GLOBALS['config']['DATADIR']).').</pre>'); | ||
95 | if ($GLOBALS['config']['ENABLE_LOCALCACHE']) | ||
96 | { | ||
97 | if (!is_dir($GLOBALS['config']['CACHEDIR'])) { mkdir($GLOBALS['config']['CACHEDIR'],0705); chmod($GLOBALS['config']['CACHEDIR'],0705); } | ||
98 | if (!is_file($GLOBALS['config']['CACHEDIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['CACHEDIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. | ||
99 | } | ||
100 | 91 | ||
101 | // Handling of old config file which do not have the new parameters. | 92 | // Handling of old config file which do not have the new parameters. |
102 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl()); | 93 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl()); |
@@ -119,13 +110,13 @@ define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GL | |||
119 | autoLocale(); // Sniff browser language and set date format accordingly. | 110 | 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. | 111 | header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. |
121 | 112 | ||
122 | // Check php version | 113 | // Check PHP version |
123 | function checkphpversion() | 114 | function checkphpversion() |
124 | { | 115 | { |
125 | if (version_compare(PHP_VERSION, '5.1.0') < 0) | 116 | if (version_compare(PHP_VERSION, '5.1.0') < 0) |
126 | { | 117 | { |
127 | header('Content-Type: text/plain; charset=utf-8'); | 118 | 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.'; | 119 | echo 'Your server supports PHP '.PHP_VERSION.'. Shaarli requires at least php 5.1.0, and thus cannot run. Sorry.'; |
129 | exit; | 120 | exit; |
130 | } | 121 | } |
131 | } | 122 | } |
@@ -144,7 +135,7 @@ function checkUpdate() | |||
144 | $version=shaarli_version; | 135 | $version=shaarli_version; |
145 | list($httpstatus,$headers,$data) = getHTTP('http://sebsauvage.net/files/shaarli_version.txt',2); | 136 | list($httpstatus,$headers,$data) = getHTTP('http://sebsauvage.net/files/shaarli_version.txt',2); |
146 | if (strpos($httpstatus,'200 OK')!==false) $version=$data; | 137 | if (strpos($httpstatus,'200 OK')!==false) $version=$data; |
147 | // If failed, nevermind. We don't want to bother the user with that. | 138 | // 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 | 139 | file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date |
149 | } | 140 | } |
150 | // Compare versions: | 141 | // Compare versions: |
@@ -160,11 +151,11 @@ function checkUpdate() | |||
160 | class pageCache | 151 | class pageCache |
161 | { | 152 | { |
162 | private $url; // Full URL of the page to cache (typically the value returned by pageUrl()) | 153 | private $url; // Full URL of the page to cache (typically the value returned by pageUrl()) |
163 | private $shouldBeCached; // boolean: Should this url be cached ? | 154 | private $shouldBeCached; // boolean: Should this url be cached? |
164 | private $filename; // Name of the cache file for this url | 155 | private $filename; // Name of the cache file for this url. |
165 | 156 | ||
166 | /* | 157 | /* |
167 | $url = url (typically the value returned by pageUrl()) | 158 | $url = URL (typically the value returned by pageUrl()) |
168 | $shouldBeCached = boolean. If false, the cache will be disabled. | 159 | $shouldBeCached = boolean. If false, the cache will be disabled. |
169 | */ | 160 | */ |
170 | public function __construct($url,$shouldBeCached) | 161 | public function __construct($url,$shouldBeCached) |
@@ -187,7 +178,6 @@ class pageCache | |||
187 | public function cache($page) | 178 | public function cache($page) |
188 | { | 179 | { |
189 | if (!$this->shouldBeCached) return; | 180 | if (!$this->shouldBeCached) return; |
190 | if (!is_dir($GLOBALS['config']['PAGECACHE'])) { mkdir($GLOBALS['config']['PAGECACHE'],0705); chmod($GLOBALS['config']['PAGECACHE'],0705); } | ||
191 | file_put_contents($this->filename,$page); | 181 | file_put_contents($this->filename,$page); |
192 | } | 182 | } |
193 | 183 | ||
@@ -227,7 +217,7 @@ function nl2br_escaped($html) | |||
227 | } | 217 | } |
228 | 218 | ||
229 | /* Returns the small hash of a string, using RFC 4648 base64url format | 219 | /* Returns the small hash of a string, using RFC 4648 base64url format |
230 | eg. smallHash('20111006_131924') --> yZH23w | 220 | e.g. smallHash('20111006_131924') --> yZH23w |
231 | Small hashes: | 221 | Small hashes: |
232 | - are unique (well, as unique as crc32, at last) | 222 | - are unique (well, as unique as crc32, at last) |
233 | - are always 6 characters long. | 223 | - are always 6 characters long. |
@@ -241,7 +231,7 @@ function smallHash($text) | |||
241 | return strtr($t, '+/', '-_'); | 231 | return strtr($t, '+/', '-_'); |
242 | } | 232 | } |
243 | 233 | ||
244 | // In a string, converts urls to clickable links. | 234 | // In a string, converts URLs to clickable links. |
245 | // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 | 235 | // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 |
246 | function text2clickable($url) | 236 | function text2clickable($url) |
247 | { | 237 | { |
@@ -262,8 +252,8 @@ function keepMultipleSpaces($text) | |||
262 | function autoLocale() | 252 | function autoLocale() |
263 | { | 253 | { |
264 | $loc='en_US'; // Default if browser does not send HTTP_ACCEPT_LANGUAGE | 254 | $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" | 255 | 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.) | 256 | { // (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]; | 257 | if (preg_match('/([a-z]{2}(-[a-z]{2})?)/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) $loc=$matches[1]; |
268 | } | 258 | } |
269 | setlocale(LC_TIME,$loc); // LC_TIME = Set local for date/time format only. | 259 | setlocale(LC_TIME,$loc); // LC_TIME = Set local for date/time format only. |
@@ -300,7 +290,7 @@ function allIPs() | |||
300 | } | 290 | } |
301 | 291 | ||
302 | function fillSessionInfo() { | 292 | function fillSessionInfo() { |
303 | $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // generate unique random number (different than phpsessionid) | 293 | $_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. | 294 | $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. |
305 | $_SESSION['username']=$GLOBALS['login']; | 295 | $_SESSION['username']=$GLOBALS['login']; |
306 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. | 296 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. |
@@ -404,7 +394,7 @@ if (isset($_POST['login'])) | |||
404 | { | 394 | { |
405 | if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.'); | 395 | 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']))) | 396 | if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password']))) |
407 | { // Login/password is ok. | 397 | { // Login/password is OK. |
408 | ban_loginOk(); | 398 | ban_loginOk(); |
409 | // If user wants to keep the session cookie even after the browser closes: | 399 | // If user wants to keep the session cookie even after the browser closes: |
410 | if (!empty($_POST['longlastingsession'])) | 400 | if (!empty($_POST['longlastingsession'])) |
@@ -415,7 +405,7 @@ if (isset($_POST['login'])) | |||
415 | 405 | ||
416 | $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; | 406 | $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 | 407 | 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 ! | 408 | // Note: Never forget the trailing slash on the cookie path! |
419 | session_regenerate_id(true); // Send cookie with new expiration date to browser. | 409 | session_regenerate_id(true); // Send cookie with new expiration date to browser. |
420 | } | 410 | } |
421 | else // Standard session expiration (=when browser closes) | 411 | else // Standard session expiration (=when browser closes) |
@@ -447,7 +437,7 @@ if (isset($_POST['login'])) | |||
447 | // Misc utility functions: | 437 | // Misc utility functions: |
448 | 438 | ||
449 | // Returns the server URL (including port and http/https), without path. | 439 | // Returns the server URL (including port and http/https), without path. |
450 | // eg. "http://myserver.com:8080" | 440 | // e.g. "http://myserver.com:8080" |
451 | // You can append $_SERVER['SCRIPT_NAME'] to get the current script URL. | 441 | // You can append $_SERVER['SCRIPT_NAME'] to get the current script URL. |
452 | function serverUrl() | 442 | function serverUrl() |
453 | { | 443 | { |
@@ -457,24 +447,24 @@ function serverUrl() | |||
457 | } | 447 | } |
458 | 448 | ||
459 | // Returns the absolute URL of current script, without the query. | 449 | // Returns the absolute URL of current script, without the query. |
460 | // (eg. http://sebsauvage.net/links/) | 450 | // (e.g. http://sebsauvage.net/links/) |
461 | function indexUrl() | 451 | function indexUrl() |
462 | { | 452 | { |
463 | $scriptname = $_SERVER["SCRIPT_NAME"]; | 453 | $scriptname = $_SERVER["SCRIPT_NAME"]; |
464 | // If the script is named 'index.php', we remove it (for better looking URLs, | 454 | // 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) | 455 | // 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); | 456 | if (endswith($scriptname,'index.php')) $scriptname = substr($scriptname,0,strlen($scriptname)-9); |
467 | return serverUrl() . $scriptname; | 457 | return serverUrl() . $scriptname; |
468 | } | 458 | } |
469 | 459 | ||
470 | // Returns the absolute URL of current script, WITH the query. | 460 | // Returns the absolute URL of current script, WITH the query. |
471 | // (eg. http://sebsauvage.net/links/?toto=titi&spamspamspam=humbug) | 461 | // (e.g. http://sebsauvage.net/links/?toto=titi&spamspamspam=humbug) |
472 | function pageUrl() | 462 | function pageUrl() |
473 | { | 463 | { |
474 | return indexUrl().(!empty($_SERVER["QUERY_STRING"]) ? '?'.$_SERVER["QUERY_STRING"] : ''); | 464 | return indexUrl().(!empty($_SERVER["QUERY_STRING"]) ? '?'.$_SERVER["QUERY_STRING"] : ''); |
475 | } | 465 | } |
476 | 466 | ||
477 | // Convert post_max_size/upload_max_filesize (eg.'16M') parameters to bytes. | 467 | // Convert post_max_size/upload_max_filesize (e.g. '16M') parameters to bytes. |
478 | function return_bytes($val) | 468 | function return_bytes($val) |
479 | { | 469 | { |
480 | $val = trim($val); $last=strtolower($val[strlen($val)-1]); | 470 | $val = trim($val); $last=strtolower($val[strlen($val)-1]); |
@@ -495,7 +485,7 @@ function getMaxFileSize() | |||
495 | $size2 = return_bytes(ini_get('upload_max_filesize')); | 485 | $size2 = return_bytes(ini_get('upload_max_filesize')); |
496 | // Return the smaller of two: | 486 | // Return the smaller of two: |
497 | $maxsize = min($size1,$size2); | 487 | $maxsize = min($size1,$size2); |
498 | // FIXME: Then convert back to readable notations ? (eg. 2M instead of 2000000) | 488 | // FIXME: Then convert back to readable notations ? (e.g. 2M instead of 2000000) |
499 | return $maxsize; | 489 | return $maxsize; |
500 | } | 490 | } |
501 | 491 | ||
@@ -543,7 +533,7 @@ function linkdate2iso8601($linkdate) | |||
543 | function linkdate2locale($linkdate) | 533 | function linkdate2locale($linkdate) |
544 | { | 534 | { |
545 | return utf8_encode(strftime('%c',linkdate2timestamp($linkdate))); // %c is for automatic date format according to locale. | 535 | 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, | 536 | // 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. | 537 | // the date will not be displayed in the chosen locale, but probably in US notation. |
548 | } | 538 | } |
549 | 539 | ||
@@ -565,10 +555,10 @@ function http_parse_headers_shaarli( $headers ) | |||
565 | } | 555 | } |
566 | 556 | ||
567 | /* GET an URL. | 557 | /* GET an URL. |
568 | Input: $url : url to get (http://...) | 558 | Input: $url : URL to get (http://...) |
569 | $timeout : Network timeout (will wait this many seconds for an anwser before giving up). | 559 | $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 | 560 | 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']) | 561 | [1] = associative array containing HTTP response headers (e.g. echo getHTTP($url)[1]['Content-Type']) |
572 | [2] = data | 562 | [2] = data |
573 | Example: list($httpstatus,$headers,$data) = getHTTP('http://sebauvage.net/'); | 563 | Example: list($httpstatus,$headers,$data) = getHTTP('http://sebauvage.net/'); |
574 | if (strpos($httpstatus,'200 OK')!==false) | 564 | if (strpos($httpstatus,'200 OK')!==false) |
@@ -584,11 +574,11 @@ function getHTTP($url,$timeout=30) | |||
584 | $context = stream_context_create($options); | 574 | $context = stream_context_create($options); |
585 | $data=file_get_contents($url,false,$context,-1, 4000000); // We download at most 4 Mb from source. | 575 | $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(),''); } | 576 | if (!$data) { return array('HTTP Error',array(),''); } |
587 | $httpStatus=$http_response_header[0]; // eg. "HTTP/1.1 200 OK" | 577 | $httpStatus=$http_response_header[0]; // e.g. "HTTP/1.1 200 OK" |
588 | $responseHeaders=http_parse_headers_shaarli($http_response_header); | 578 | $responseHeaders=http_parse_headers_shaarli($http_response_header); |
589 | return array($httpStatus,$responseHeaders,$data); | 579 | return array($httpStatus,$responseHeaders,$data); |
590 | } | 580 | } |
591 | catch (Exception $e) // getHTTP *can* fail silentely (we don't care if the title cannot be fetched) | 581 | catch (Exception $e) // getHTTP *can* fail silently (we don't care if the title cannot be fetched) |
592 | { | 582 | { |
593 | return array($e->getMessage(),'',''); | 583 | return array($e->getMessage(),'',''); |
594 | } | 584 | } |
@@ -614,14 +604,14 @@ function getToken() | |||
614 | return $rnd; | 604 | return $rnd; |
615 | } | 605 | } |
616 | 606 | ||
617 | // Tells if a token is ok. Using this function will destroy the token. | 607 | // Tells if a token is OK. Using this function will destroy the token. |
618 | // true=token is ok. | 608 | // true=token is OK. |
619 | function tokenOk($token) | 609 | function tokenOk($token) |
620 | { | 610 | { |
621 | if (isset($_SESSION['tokens'][$token])) | 611 | if (isset($_SESSION['tokens'][$token])) |
622 | { | 612 | { |
623 | unset($_SESSION['tokens'][$token]); // Token is used: destroy it. | 613 | unset($_SESSION['tokens'][$token]); // Token is used: destroy it. |
624 | return true; // Token is ok. | 614 | return true; // Token is OK. |
625 | } | 615 | } |
626 | return false; // Wrong token, or already used. | 616 | return false; // Wrong token, or already used. |
627 | } | 617 | } |
@@ -656,7 +646,7 @@ class pageBuilder | |||
656 | $this->tpl->assign('version',shaarli_version); | 646 | $this->tpl->assign('version',shaarli_version); |
657 | $this->tpl->assign('scripturl',indexUrl()); | 647 | $this->tpl->assign('scripturl',indexUrl()); |
658 | $this->tpl->assign('pagetitle','Shaarli'); | 648 | $this->tpl->assign('pagetitle','Shaarli'); |
659 | $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ? | 649 | $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links? |
660 | if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']); | 650 | if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']); |
661 | if (!empty($GLOBALS['titleLink'])) $this->tpl->assign('titleLink',$GLOBALS['titleLink']); | 651 | if (!empty($GLOBALS['titleLink'])) $this->tpl->assign('titleLink',$GLOBALS['titleLink']); |
662 | if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']); | 652 | if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']); |
@@ -672,7 +662,7 @@ class pageBuilder | |||
672 | } | 662 | } |
673 | 663 | ||
674 | // Render a specific page (using a template). | 664 | // Render a specific page (using a template). |
675 | // eg. pb.renderPage('picwall') | 665 | // e.g. pb.renderPage('picwall') |
676 | public function renderPage($page) | 666 | public function renderPage($page) |
677 | { | 667 | { |
678 | if ($this->tpl===false) $this->initialize(); // Lazy initialization | 668 | if ($this->tpl===false) $this->initialize(); // Lazy initialization |
@@ -691,10 +681,10 @@ class pageBuilder | |||
691 | 681 | ||
692 | Available keys: | 682 | Available keys: |
693 | title : Title of the link | 683 | title : Title of the link |
694 | url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (eg.'?m-ukcw') | 684 | url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (e.g.'?m-ukcw') |
695 | description : description of the entry | 685 | description : description of the entry |
696 | private : Is this link private ? 0=no, other value=yes | 686 | 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') | 687 | 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) | 688 | tags : tags attached to this entry (separated by spaces) |
699 | 689 | ||
700 | We implement 3 interfaces: | 690 | We implement 3 interfaces: |
@@ -704,15 +694,15 @@ class pageBuilder | |||
704 | */ | 694 | */ |
705 | class linkdb implements Iterator, Countable, ArrayAccess | 695 | class linkdb implements Iterator, Countable, ArrayAccess |
706 | { | 696 | { |
707 | private $links; // List of links (associative array. Key=linkdate (eg. "20110823_124546"), value= associative array (keys:title,description...) | 697 | 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) | 698 | 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) | 699 | 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.) | 700 | 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) | 701 | private $loggedin; // Is the user logged in? (used to filter private links) |
712 | 702 | ||
713 | // Constructor: | 703 | // Constructor: |
714 | function __construct($isLoggedIn) | 704 | function __construct($isLoggedIn) |
715 | // Input : $isLoggedIn : is the used logged in ? | 705 | // Input : $isLoggedIn : is the user logged in? |
716 | { | 706 | { |
717 | $this->loggedin = $isLoggedIn; | 707 | $this->loggedin = $isLoggedIn; |
718 | $this->checkdb(); // Make sure data file exists. | 708 | $this->checkdb(); // Make sure data file exists. |
@@ -726,7 +716,7 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
726 | public function offsetSet($offset, $value) | 716 | public function offsetSet($offset, $value) |
727 | { | 717 | { |
728 | if (!$this->loggedin) die('You are not authorized to add a link.'); | 718 | 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.'); | 719 | 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.'); | 720 | if (empty($offset)) die('You must specify a key.'); |
731 | $this->links[$offset] = $value; | 721 | $this->links[$offset] = $value; |
732 | $this->urls[$value['url']]=$offset; | 722 | $this->urls[$value['url']]=$offset; |
@@ -789,19 +779,19 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
789 | invalidateCaches(); | 779 | invalidateCaches(); |
790 | } | 780 | } |
791 | 781 | ||
792 | // Returns the link for a given URL (if it exists). false it does not exist. | 782 | // Returns the link for a given URL (if it exists). False if it does not exist. |
793 | public function getLinkFromUrl($url) | 783 | public function getLinkFromUrl($url) |
794 | { | 784 | { |
795 | if (isset($this->urls[$url])) return $this->links[$this->urls[$url]]; | 785 | if (isset($this->urls[$url])) return $this->links[$this->urls[$url]]; |
796 | return false; | 786 | return false; |
797 | } | 787 | } |
798 | 788 | ||
799 | // Case insentitive search among links (in url, title and description). Returns filtered list of links. | 789 | // Case insensitive search among links (in the URLs, title and description). Returns filtered list of links. |
800 | // eg. print_r($mydb->filterFulltext('hollandais')); | 790 | // e.g. print_r($mydb->filterFulltext('hollandais')); |
801 | public function filterFulltext($searchterms) | 791 | public function filterFulltext($searchterms) |
802 | { | 792 | { |
803 | // FIXME: explode(' ',$searchterms) and perform a AND search. | 793 | // FIXME: explode(' ',$searchterms) and perform a AND search. |
804 | // FIXME: accept double-quotes to search for a string "as is" ? | 794 | // FIXME: accept double-quotes to search for a string "as is"? |
805 | $filtered=array(); | 795 | $filtered=array(); |
806 | $s = strtolower($searchterms); | 796 | $s = strtolower($searchterms); |
807 | foreach($this->links as $l) | 797 | foreach($this->links as $l) |
@@ -818,7 +808,7 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
818 | 808 | ||
819 | // Filter by tag. | 809 | // Filter by tag. |
820 | // You can specify one or more tags (tags can be separated by space or comma). | 810 | // You can specify one or more tags (tags can be separated by space or comma). |
821 | // eg. print_r($mydb->filterTags('linux programming')); | 811 | // e.g. print_r($mydb->filterTags('linux programming')); |
822 | public function filterTags($tags,$casesensitive=false) | 812 | public function filterTags($tags,$casesensitive=false) |
823 | { | 813 | { |
824 | $t = str_replace(',',' ',($casesensitive?$tags:strtolower($tags))); | 814 | $t = str_replace(',',' ',($casesensitive?$tags:strtolower($tags))); |
@@ -834,9 +824,9 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
834 | return $filtered; | 824 | return $filtered; |
835 | } | 825 | } |
836 | 826 | ||
837 | // Filter by day. Day must be in the form 'YYYYMMDD' (eg. '20120125') | 827 | // Filter by day. Day must be in the form 'YYYYMMDD' (e.g. '20120125') |
838 | // Sort order is: older articles first. | 828 | // Sort order is: older articles first. |
839 | // eg. print_r($mydb->filterDay('20120125')); | 829 | // e.g. print_r($mydb->filterDay('20120125')); |
840 | public function filterDay($day) | 830 | public function filterDay($day) |
841 | { | 831 | { |
842 | $filtered=array(); | 832 | $filtered=array(); |
@@ -891,13 +881,13 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
891 | } | 881 | } |
892 | 882 | ||
893 | // ------------------------------------------------------------------------------------------ | 883 | // ------------------------------------------------------------------------------------------ |
894 | // Ouput the last N links in RSS 2.0 format. | 884 | // Output the last N links in RSS 2.0 format. |
895 | function showRSS() | 885 | function showRSS() |
896 | { | 886 | { |
897 | header('Content-Type: application/rss+xml; charset=utf-8'); | 887 | header('Content-Type: application/rss+xml; charset=utf-8'); |
898 | 888 | ||
899 | // $usepermalink : If true, use permalink instead of final link. | 889 | // $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 | 890 | // User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=rss&permalinks |
901 | $usepermalinks = isset($_GET['permalinks']); | 891 | $usepermalinks = isset($_GET['permalinks']); |
902 | 892 | ||
903 | // Cache system | 893 | // Cache system |
@@ -906,9 +896,9 @@ function showRSS() | |||
906 | $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } | 896 | $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } |
907 | 897 | ||
908 | // If cached was not found (or not usable), then read the database and build the response: | 898 | // 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). | 899 | $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if user it not logged in). |
910 | 900 | ||
911 | // Optionnaly filter the results: | 901 | // Optionally filter the results: |
912 | $linksToDisplay=array(); | 902 | $linksToDisplay=array(); |
913 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); | 903 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); |
914 | elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 904 | elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
@@ -965,13 +955,13 @@ function showRSS() | |||
965 | } | 955 | } |
966 | 956 | ||
967 | // ------------------------------------------------------------------------------------------ | 957 | // ------------------------------------------------------------------------------------------ |
968 | // Ouput the last N links in ATOM format. | 958 | // Output the last N links in ATOM format. |
969 | function showATOM() | 959 | function showATOM() |
970 | { | 960 | { |
971 | header('Content-Type: application/atom+xml; charset=utf-8'); | 961 | header('Content-Type: application/atom+xml; charset=utf-8'); |
972 | 962 | ||
973 | // $usepermalink : If true, use permalink instead of final link. | 963 | // $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 | 964 | // User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=atom&permalinks |
975 | $usepermalinks = isset($_GET['permalinks']); | 965 | $usepermalinks = isset($_GET['permalinks']); |
976 | 966 | ||
977 | // Cache system | 967 | // Cache system |
@@ -983,7 +973,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). | 973 | $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). |
984 | 974 | ||
985 | 975 | ||
986 | // Optionnaly filter the results: | 976 | // Optionally filter the results: |
987 | $linksToDisplay=array(); | 977 | $linksToDisplay=array(); |
988 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); | 978 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); |
989 | elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 979 | elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
@@ -1079,7 +1069,7 @@ function showDailyRSS() | |||
1079 | if (empty($days[$day])) $days[$day]=array(); | 1069 | if (empty($days[$day])) $days[$day]=array(); |
1080 | $days[$day][]=$linkdate; | 1070 | $days[$day][]=$linkdate; |
1081 | } | 1071 | } |
1082 | if (count($days)>$nb_of_days) break; // Have we collected enough days ? | 1072 | if (count($days)>$nb_of_days) break; // Have we collected enough days? |
1083 | } | 1073 | } |
1084 | 1074 | ||
1085 | // Build the RSS feed. | 1075 | // Build the RSS feed. |
@@ -1158,7 +1148,7 @@ function showDaily() | |||
1158 | } | 1148 | } |
1159 | 1149 | ||
1160 | /* We need to spread the articles on 3 columns. | 1150 | /* We need to spread the articles on 3 columns. |
1161 | I did not want to use a javascript lib like http://masonry.desandro.com/ | 1151 | 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 | 1152 | so I manually spread entries with a simple method: I roughly evaluate the |
1163 | height of a div according to title and description length. | 1153 | height of a div according to title and description length. |
1164 | */ | 1154 | */ |
@@ -1169,7 +1159,7 @@ function showDaily() | |||
1169 | // Roughly estimate length of entry (by counting characters) | 1159 | // Roughly estimate length of entry (by counting characters) |
1170 | // Title: 30 chars = 1 line. 1 line is 30 pixels height. | 1160 | // Title: 30 chars = 1 line. 1 line is 30 pixels height. |
1171 | // Description: 836 characters gives roughly 342 pixel height. | 1161 | // Description: 836 characters gives roughly 342 pixel height. |
1172 | // This is not perfect, but it's usually ok. | 1162 | // This is not perfect, but it's usually OK. |
1173 | $length=strlen($link['title'])+(342*strlen($link['description']))/836; | 1163 | $length=strlen($link['title'])+(342*strlen($link['description']))/836; |
1174 | if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height. | 1164 | if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height. |
1175 | // Then put in column which is the less filled: | 1165 | // Then put in column which is the less filled: |
@@ -1222,7 +1212,7 @@ function renderPage() | |||
1222 | // -------- Picture wall | 1212 | // -------- Picture wall |
1223 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=picwall')) | 1213 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=picwall')) |
1224 | { | 1214 | { |
1225 | // Optionnaly filter the results: | 1215 | // Optionally filter the results: |
1226 | $links=array(); | 1216 | $links=array(); |
1227 | if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); | 1217 | if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); |
1228 | elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 1218 | elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
@@ -1302,7 +1292,7 @@ function renderPage() | |||
1302 | if (isset($_GET['linksperpage'])) | 1292 | if (isset($_GET['linksperpage'])) |
1303 | { | 1293 | { |
1304 | if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); } | 1294 | if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); } |
1305 | // Make sure the referer is from Shaarli itself. | 1295 | // Make sure the referrer is Shaarli itself. |
1306 | $referer = '?'; | 1296 | $referer = '?'; |
1307 | if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) | 1297 | if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) |
1308 | $referer = $_SERVER['HTTP_REFERER']; | 1298 | $referer = $_SERVER['HTTP_REFERER']; |
@@ -1321,7 +1311,7 @@ function renderPage() | |||
1321 | { | 1311 | { |
1322 | unset($_SESSION['privateonly']); // See all links | 1312 | unset($_SESSION['privateonly']); // See all links |
1323 | } | 1313 | } |
1324 | // Make sure the referer is from Shaarli itself. | 1314 | // Make sure the referrer is Shaarli itself. |
1325 | $referer = '?'; | 1315 | $referer = '?'; |
1326 | if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) | 1316 | if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) |
1327 | $referer = $_SERVER['HTTP_REFERER']; | 1317 | $referer = $_SERVER['HTTP_REFERER']; |
@@ -1332,7 +1322,7 @@ function renderPage() | |||
1332 | // -------- Handle other actions allowed for non-logged in users: | 1322 | // -------- Handle other actions allowed for non-logged in users: |
1333 | if (!isLoggedIn()) | 1323 | if (!isLoggedIn()) |
1334 | { | 1324 | { |
1335 | // User tries to post new link but is not loggedin: | 1325 | // User tries to post new link but is not logged in: |
1336 | // Show login screen, then redirect to ?post=... | 1326 | // Show login screen, then redirect to ?post=... |
1337 | if (isset($_GET['post'])) | 1327 | if (isset($_GET['post'])) |
1338 | { | 1328 | { |
@@ -1342,7 +1332,7 @@ function renderPage() | |||
1342 | $PAGE = new pageBuilder; | 1332 | $PAGE = new pageBuilder; |
1343 | buildLinkList($PAGE,$LINKSDB); // Compute list of links to display | 1333 | buildLinkList($PAGE,$LINKSDB); // Compute list of links to display |
1344 | $PAGE->renderPage('linklist'); | 1334 | $PAGE->renderPage('linklist'); |
1345 | exit; // Never remove this one ! All operations below are reserved for logged in user. | 1335 | exit; // Never remove this one! All operations below are reserved for logged in user. |
1346 | } | 1336 | } |
1347 | 1337 | ||
1348 | // -------- All other functions are reserved for the registered user: | 1338 | // -------- All other functions are reserved for the registered user: |
@@ -1363,7 +1353,7 @@ function renderPage() | |||
1363 | if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.'); | 1353 | 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'])) | 1354 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) |
1365 | { | 1355 | { |
1366 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! | 1356 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! |
1367 | 1357 | ||
1368 | // Make sure old password is correct. | 1358 | // Make sure old password is correct. |
1369 | $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1359 | $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']); |
@@ -1390,7 +1380,7 @@ function renderPage() | |||
1390 | { | 1380 | { |
1391 | if (!empty($_POST['title']) ) | 1381 | if (!empty($_POST['title']) ) |
1392 | { | 1382 | { |
1393 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! | 1383 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! |
1394 | $tz = 'UTC'; | 1384 | $tz = 'UTC'; |
1395 | if (!empty($_POST['continent']) && !empty($_POST['city'])) | 1385 | if (!empty($_POST['continent']) && !empty($_POST['city'])) |
1396 | if (isTZvalid($_POST['continent'],$_POST['city'])) | 1386 | if (isTZvalid($_POST['continent'],$_POST['city'])) |
@@ -1414,7 +1404,7 @@ function renderPage() | |||
1414 | $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); | 1404 | $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); |
1415 | $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); | 1405 | $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); |
1416 | list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); | 1406 | list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); |
1417 | $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ? | 1407 | $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template? |
1418 | $PAGE->assign('timezone_js',$timezone_js); | 1408 | $PAGE->assign('timezone_js',$timezone_js); |
1419 | $PAGE->renderPage('configure'); | 1409 | $PAGE->renderPage('configure'); |
1420 | exit; | 1410 | exit; |
@@ -1438,7 +1428,7 @@ function renderPage() | |||
1438 | if (!empty($_POST['deletetag']) && !empty($_POST['fromtag'])) | 1428 | if (!empty($_POST['deletetag']) && !empty($_POST['fromtag'])) |
1439 | { | 1429 | { |
1440 | $needle=trim($_POST['fromtag']); | 1430 | $needle=trim($_POST['fromtag']); |
1441 | $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. | 1431 | $linksToAlter = $LINKSDB->filterTags($needle,true); // True for case-sensitive tag search. |
1442 | foreach($linksToAlter as $key=>$value) | 1432 | foreach($linksToAlter as $key=>$value) |
1443 | { | 1433 | { |
1444 | $tags = explode(' ',trim($value['tags'])); | 1434 | $tags = explode(' ',trim($value['tags'])); |
@@ -1446,7 +1436,7 @@ function renderPage() | |||
1446 | $value['tags']=trim(implode(' ',$tags)); | 1436 | $value['tags']=trim(implode(' ',$tags)); |
1447 | $LINKSDB[$key]=$value; | 1437 | $LINKSDB[$key]=$value; |
1448 | } | 1438 | } |
1449 | $LINKSDB->savedb(); // save to disk | 1439 | $LINKSDB->savedb(); // Save to disk. |
1450 | echo '<script language="JavaScript">alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>'; | 1440 | echo '<script language="JavaScript">alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>'; |
1451 | exit; | 1441 | exit; |
1452 | } | 1442 | } |
@@ -1459,17 +1449,17 @@ function renderPage() | |||
1459 | foreach($linksToAlter as $key=>$value) | 1449 | foreach($linksToAlter as $key=>$value) |
1460 | { | 1450 | { |
1461 | $tags = explode(' ',trim($value['tags'])); | 1451 | $tags = explode(' ',trim($value['tags'])); |
1462 | $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Remplace tags value. | 1452 | $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Replace tags value. |
1463 | $value['tags']=trim(implode(' ',$tags)); | 1453 | $value['tags']=trim(implode(' ',$tags)); |
1464 | $LINKSDB[$key]=$value; | 1454 | $LINKSDB[$key]=$value; |
1465 | } | 1455 | } |
1466 | $LINKSDB->savedb(); // save to disk | 1456 | $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>'; | 1457 | echo '<script language="JavaScript">alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>'; |
1468 | exit; | 1458 | exit; |
1469 | } | 1459 | } |
1470 | } | 1460 | } |
1471 | 1461 | ||
1472 | // -------- User wants to add a link without using the bookmarklet: show form. | 1462 | // -------- User wants to add a link without using the bookmarklet: Show form. |
1473 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink')) | 1463 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink')) |
1474 | { | 1464 | { |
1475 | $PAGE = new pageBuilder; | 1465 | $PAGE = new pageBuilder; |
@@ -1481,7 +1471,7 @@ function renderPage() | |||
1481 | // -------- User clicked the "Save" button when editing a link: Save link to database. | 1471 | // -------- User clicked the "Save" button when editing a link: Save link to database. |
1482 | if (isset($_POST['save_edit'])) | 1472 | if (isset($_POST['save_edit'])) |
1483 | { | 1473 | { |
1484 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! | 1474 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! |
1485 | $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. | 1475 | $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. |
1486 | $linkdate=$_POST['lf_linkdate']; | 1476 | $linkdate=$_POST['lf_linkdate']; |
1487 | $url = trim($_POST['lf_url']); | 1477 | $url = trim($_POST['lf_url']); |
@@ -1491,7 +1481,7 @@ function renderPage() | |||
1491 | 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags)); | 1481 | 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags)); |
1492 | if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. | 1482 | if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. |
1493 | $LINKSDB[$linkdate] = $link; | 1483 | $LINKSDB[$linkdate] = $link; |
1494 | $LINKSDB->savedb(); // save to disk | 1484 | $LINKSDB->savedb(); // Save to disk. |
1495 | pubsubhub(); | 1485 | pubsubhub(); |
1496 | 1486 | ||
1497 | // If we are called from the bookmarklet, we must close the popup: | 1487 | // If we are called from the bookmarklet, we must close the popup: |
@@ -1505,7 +1495,7 @@ function renderPage() | |||
1505 | // -------- User clicked the "Cancel" button when editing a link. | 1495 | // -------- User clicked the "Cancel" button when editing a link. |
1506 | if (isset($_POST['cancel_edit'])) | 1496 | if (isset($_POST['cancel_edit'])) |
1507 | { | 1497 | { |
1508 | // If we are called from the bookmarklet, we must close the popup; | 1498 | // 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; } | 1499 | if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo '<script language="JavaScript">self.close();</script>'; exit; } |
1510 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); | 1500 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); |
1511 | $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. | 1501 | $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. |
@@ -1513,12 +1503,12 @@ function renderPage() | |||
1513 | exit; | 1503 | exit; |
1514 | } | 1504 | } |
1515 | 1505 | ||
1516 | // -------- User clicked the "Delete" button when editing a link : Delete link from database. | 1506 | // -------- User clicked the "Delete" button when editing a link: Delete link from database. |
1517 | if (isset($_POST['delete_link'])) | 1507 | if (isset($_POST['delete_link'])) |
1518 | { | 1508 | { |
1519 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | 1509 | if (!tokenOk($_POST['token'])) die('Wrong token.'); |
1520 | // We do not need to ask for confirmation: | 1510 | // We do not need to ask for confirmation: |
1521 | // - confirmation is handled by javascript | 1511 | // - confirmation is handled by JavaScript |
1522 | // - we are protected from XSRF by the token. | 1512 | // - we are protected from XSRF by the token. |
1523 | $linkdate=$_POST['lf_linkdate']; | 1513 | $linkdate=$_POST['lf_linkdate']; |
1524 | unset($LINKSDB[$linkdate]); | 1514 | unset($LINKSDB[$linkdate]); |
@@ -1568,7 +1558,7 @@ function renderPage() | |||
1568 | $tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL | 1558 | $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 | 1559 | $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; | 1560 | 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.) | 1561 | // 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') | 1562 | if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http') |
1573 | { | 1563 | { |
1574 | list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive. | 1564 | list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive. |
@@ -1622,7 +1612,7 @@ function renderPage() | |||
1622 | exit; | 1612 | exit; |
1623 | } | 1613 | } |
1624 | $exportWhat=$_GET['what']; | 1614 | $exportWhat=$_GET['what']; |
1625 | if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???'); | 1615 | if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export???'); |
1626 | 1616 | ||
1627 | header('Content-Type: text/html; charset=utf-8'); | 1617 | header('Content-Type: text/html; charset=utf-8'); |
1628 | header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html'); | 1618 | header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html'); |
@@ -1695,8 +1685,8 @@ function importFile() | |||
1695 | $filename=$_FILES['filetoupload']['name']; | 1685 | $filename=$_FILES['filetoupload']['name']; |
1696 | $filesize=$_FILES['filetoupload']['size']; | 1686 | $filesize=$_FILES['filetoupload']['size']; |
1697 | $data=file_get_contents($_FILES['filetoupload']['tmp_name']); | 1687 | $data=file_get_contents($_FILES['filetoupload']['tmp_name']); |
1698 | $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private ? | 1688 | $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 ? | 1689 | $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones? |
1700 | $import_count=0; | 1690 | $import_count=0; |
1701 | 1691 | ||
1702 | // Sniff file type: | 1692 | // Sniff file type: |
@@ -1707,7 +1697,7 @@ function importFile() | |||
1707 | if ($type=='netscape') | 1697 | if ($type=='netscape') |
1708 | { | 1698 | { |
1709 | // This is a standard Netscape-style bookmark file. | 1699 | // 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. | 1700 | // 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 | 1701 | foreach(explode('<DT>',$data) as $html) // explode is very fast |
1712 | { | 1702 | { |
1713 | $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); | 1703 | $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); |
@@ -1741,14 +1731,14 @@ function importFile() | |||
1741 | 1731 | ||
1742 | // Make sure date/time is not already used by another link. | 1732 | // Make sure date/time is not already used by another link. |
1743 | // (Some bookmark files have several different links with the same ADD_DATE) | 1733 | // (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. | 1734 | // 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.) | 1735 | // (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. | 1736 | 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); | 1737 | $link['linkdate']=date('Ymd_His',$raw_add_date); |
1748 | $LINKSDB[$link['linkdate']] = $link; | 1738 | $LINKSDB[$link['linkdate']] = $link; |
1749 | $import_count++; | 1739 | $import_count++; |
1750 | } | 1740 | } |
1751 | else // link already present in database. | 1741 | else // Link already present in database. |
1752 | { | 1742 | { |
1753 | if ($overwrite) | 1743 | if ($overwrite) |
1754 | { // If overwrite is required, we import link data, except date/time. | 1744 | { // If overwrite is required, we import link data, except date/time. |
@@ -1799,13 +1789,13 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1799 | { | 1789 | { |
1800 | header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); | 1790 | 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.'; | 1791 | 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> ?'; | 1792 | echo '<br>You would mind <a href="?">clicking here</a>?'; |
1803 | exit; | 1793 | exit; |
1804 | } | 1794 | } |
1805 | $search_type='permalink'; | 1795 | $search_type='permalink'; |
1806 | } | 1796 | } |
1807 | else | 1797 | else |
1808 | $linksToDisplay = $LINKSDB; // otherwise, display without filtering. | 1798 | $linksToDisplay = $LINKSDB; // Otherwise, display without filtering. |
1809 | 1799 | ||
1810 | // Option: Show only private links | 1800 | // Option: Show only private links |
1811 | if (!empty($_SESSION['privateonly'])) | 1801 | if (!empty($_SESSION['privateonly'])) |
@@ -1819,11 +1809,11 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1819 | } | 1809 | } |
1820 | 1810 | ||
1821 | // ---- Handle paging. | 1811 | // ---- 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 ??? | 1812 | /* 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 ... " | 1813 | "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); ) | 1814 | If my class implements ArrayAccess, why won't array_keys() accept it ? ( $keys=array_keys($linksToDisplay); ) |
1825 | */ | 1815 | */ |
1826 | $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks php. | 1816 | $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks PHP. |
1827 | 1817 | ||
1828 | // If there is only a single link, we change on-the-fly the title of the page. | 1818 | // 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']; | 1819 | if (count($linksToDisplay)==1) $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; |
@@ -1870,7 +1860,7 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1870 | $PAGE->assign('result_count',count($linksToDisplay)); | 1860 | $PAGE->assign('result_count',count($linksToDisplay)); |
1871 | $PAGE->assign('search_type',$search_type); | 1861 | $PAGE->assign('search_type',$search_type); |
1872 | $PAGE->assign('search_crits',$search_crits); | 1862 | $PAGE->assign('search_crits',$search_crits); |
1873 | $PAGE->assign('redirector',empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']); // optional redirector URL | 1863 | $PAGE->assign('redirector',empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']); // Optional redirector URL. |
1874 | $PAGE->assign('token',$token); | 1864 | $PAGE->assign('token',$token); |
1875 | $PAGE->assign('links',$linkDisp); | 1865 | $PAGE->assign('links',$linkDisp); |
1876 | return; | 1866 | return; |
@@ -1878,9 +1868,9 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1878 | 1868 | ||
1879 | // Compute the thumbnail for a link. | 1869 | // Compute the thumbnail for a link. |
1880 | // | 1870 | // |
1881 | // with a link to the original URL. | 1871 | // With a link to the original URL. |
1882 | // Understands various services (youtube.com...) | 1872 | // Understands various services (youtube.com...) |
1883 | // Input: $url = url for which the thumbnail must be found. | 1873 | // Input: $url = URL for which the thumbnail must be found. |
1884 | // $href = if provided, this URL will be followed instead of $url | 1874 | // $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) | 1875 | // Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) |
1886 | // Some of them may be missing. | 1876 | // Some of them may be missing. |
@@ -1891,7 +1881,7 @@ function computeThumbnail($url,$href=false) | |||
1891 | if ($href==false) $href=$url; | 1881 | if ($href==false) $href=$url; |
1892 | 1882 | ||
1893 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. | 1883 | // 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 ) | 1884 | // (e.g. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg ) |
1895 | // ^^^^^^^^^^^ ^^^^^^^^^^^ | 1885 | // ^^^^^^^^^^^ ^^^^^^^^^^^ |
1896 | $domain = parse_url($url,PHP_URL_HOST); | 1886 | $domain = parse_url($url,PHP_URL_HOST); |
1897 | if ($domain=='youtube.com' || $domain=='www.youtube.com') | 1887 | if ($domain=='youtube.com' || $domain=='www.youtube.com') |
@@ -1964,17 +1954,17 @@ function computeThumbnail($url,$href=false) | |||
1964 | ) | 1954 | ) |
1965 | { | 1955 | { |
1966 | if ($domain=='vimeo.com') | 1956 | if ($domain=='vimeo.com') |
1967 | { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric) | 1957 | { // Make sure this vimeo URL points to a video (/xxx... where xxx is numeric) |
1968 | $path = parse_url($url,PHP_URL_PATH); | 1958 | $path = parse_url($url,PHP_URL_PATH); |
1969 | if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL. | 1959 | if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL. |
1970 | } | 1960 | } |
1971 | if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) | 1961 | if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) |
1972 | { // Make sure this url points to a single comic (/xxx... where xxx is numeric) | 1962 | { // Make sure this URL points to a single comic (/xxx... where xxx is numeric) |
1973 | $path = parse_url($url,PHP_URL_PATH); | 1963 | $path = parse_url($url,PHP_URL_PATH); |
1974 | if (!preg_match('!/\d+.+?!',$path)) return array(); | 1964 | if (!preg_match('!/\d+.+?!',$path)) return array(); |
1975 | } | 1965 | } |
1976 | if ($domain=='ted.com' || endsWith($domain,'.ted.com')) | 1966 | if ($domain=='ted.com' || endsWith($domain,'.ted.com')) |
1977 | { // Make sure this TED url points to a video (/talks/...) | 1967 | { // Make sure this TED URL points to a video (/talks/...) |
1978 | $path = parse_url($url,PHP_URL_PATH); | 1968 | $path = parse_url($url,PHP_URL_PATH); |
1979 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. | 1969 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. |
1980 | } | 1970 | } |
@@ -2001,7 +1991,7 @@ function computeThumbnail($url,$href=false) | |||
2001 | // Returns the HTML code to display a thumbnail for a link | 1991 | // Returns the HTML code to display a thumbnail for a link |
2002 | // with a link to the original URL. | 1992 | // with a link to the original URL. |
2003 | // Understands various services (youtube.com...) | 1993 | // Understands various services (youtube.com...) |
2004 | // Input: $url = url for which the thumbnail must be found. | 1994 | // Input: $url = URL for which the thumbnail must be found. |
2005 | // $href = if provided, this URL will be followed instead of $url | 1995 | // $href = if provided, this URL will be followed instead of $url |
2006 | // Returns '' if no thumbnail available. | 1996 | // Returns '' if no thumbnail available. |
2007 | function thumbnail($url,$href=false) | 1997 | function thumbnail($url,$href=false) |
@@ -2022,7 +2012,7 @@ function thumbnail($url,$href=false) | |||
2022 | // Returns the HTML code to display a thumbnail for a link | 2012 | // Returns the HTML code to display a thumbnail for a link |
2023 | // for the picture wall (using lazy image loading) | 2013 | // for the picture wall (using lazy image loading) |
2024 | // Understands various services (youtube.com...) | 2014 | // Understands various services (youtube.com...) |
2025 | // Input: $url = url for which the thumbnail must be found. | 2015 | // Input: $url = URL for which the thumbnail must be found. |
2026 | // $href = if provided, this URL will be followed instead of $url | 2016 | // $href = if provided, this URL will be followed instead of $url |
2027 | // Returns '' if no thumbnail available. | 2017 | // Returns '' if no thumbnail available. |
2028 | function lazyThumbnail($url,$href=false) | 2018 | function lazyThumbnail($url,$href=false) |
@@ -2032,7 +2022,7 @@ function lazyThumbnail($url,$href=false) | |||
2032 | 2022 | ||
2033 | $html='<a href="'.htmlspecialchars($t['href']).'">'; | 2023 | $html='<a href="'.htmlspecialchars($t['href']).'">'; |
2034 | 2024 | ||
2035 | // Lazy image (only loaded by javascript when in the viewport). | 2025 | // Lazy image (only loaded by JavaScript when in the viewport). |
2036 | if (!empty($GLOBALS['disablejquery'])) // (except if jQuery is disabled) | 2026 | if (!empty($GLOBALS['disablejquery'])) // (except if jQuery is disabled) |
2037 | $html.='<img class="lazyimage" src="'.htmlspecialchars($t['src']).'"'; | 2027 | $html.='<img class="lazyimage" src="'.htmlspecialchars($t['src']).'"'; |
2038 | else | 2028 | else |
@@ -2044,7 +2034,7 @@ function lazyThumbnail($url,$href=false) | |||
2044 | if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; | 2034 | if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; |
2045 | $html.='>'; | 2035 | $html.='>'; |
2046 | 2036 | ||
2047 | // No-javascript fallback. | 2037 | // No-JavaScript fallback. |
2048 | $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"'; | 2038 | $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"'; |
2049 | if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; | 2039 | if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; |
2050 | if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; | 2040 | if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; |
@@ -2081,7 +2071,7 @@ function install() | |||
2081 | header('Location: '.indexUrl().'?test_session'); // Redirect to check stored data. | 2071 | header('Location: '.indexUrl().'?test_session'); // Redirect to check stored data. |
2082 | } | 2072 | } |
2083 | if (isset($_GET['test_session'])) | 2073 | if (isset($_GET['test_session'])) |
2084 | { // Step 3: Sessions are ok. Remove test parameter from URL. | 2074 | { // Step 3: Sessions are OK. Remove test parameter from URL. |
2085 | header('Location: '.indexUrl()); | 2075 | header('Location: '.indexUrl()); |
2086 | } | 2076 | } |
2087 | 2077 | ||
@@ -2099,7 +2089,7 @@ function install() | |||
2099 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 2089 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); |
2100 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] ); | 2090 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] ); |
2101 | writeConfig(); | 2091 | 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>'; | 2092 | 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; | 2093 | exit; |
2104 | } | 2094 | } |
2105 | 2095 | ||
@@ -2114,14 +2104,14 @@ function install() | |||
2114 | exit; | 2104 | exit; |
2115 | } | 2105 | } |
2116 | 2106 | ||
2117 | // Generates the timezone selection form and javascript. | 2107 | // Generates the timezone selection form and JavaScript. |
2118 | // Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected. | 2108 | // Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected. |
2119 | // Output: array(html,js) | 2109 | // Output: array(html,js) |
2120 | // Example: list($htmlform,$js) = templateTZform('Europe/Paris'); // Europe/Paris pre-selected. | 2110 | // 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) | 2111 | // Returns array('','') if server does not support timezones list. (e.g. PHP 5.1 on free.fr) |
2122 | function templateTZform($ptz=false) | 2112 | function templateTZform($ptz=false) |
2123 | { | 2113 | { |
2124 | if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr | 2114 | if (function_exists('timezone_identifiers_list')) // because of old PHP version (5.1) which can be found on free.fr |
2125 | { | 2115 | { |
2126 | // Try to split the provided timezone. | 2116 | // Try to split the provided timezone. |
2127 | if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; } | 2117 | if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; } |
@@ -2130,7 +2120,7 @@ function templateTZform($ptz=false) | |||
2130 | // Display config form: | 2120 | // Display config form: |
2131 | $timezone_form = ''; | 2121 | $timezone_form = ''; |
2132 | $timezone_js = ''; | 2122 | $timezone_js = ''; |
2133 | // The list is in the forme "Europe/Paris", "America/Argentina/Buenos_Aires"... | 2123 | // The list is in the form "Europe/Paris", "America/Argentina/Buenos_Aires"... |
2134 | // We split the list in continents/cities. | 2124 | // We split the list in continents/cities. |
2135 | $continents = array(); | 2125 | $continents = array(); |
2136 | $cities = array(); | 2126 | $cities = array(); |
@@ -2168,9 +2158,9 @@ function templateTZform($ptz=false) | |||
2168 | function isTZvalid($continent,$city) | 2158 | function isTZvalid($continent,$city) |
2169 | { | 2159 | { |
2170 | $tz = $continent.'/'.$city; | 2160 | $tz = $continent.'/'.$city; |
2171 | if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr | 2161 | if (function_exists('timezone_identifiers_list')) // because of old PHP version (5.1) which can be found on free.fr |
2172 | { | 2162 | { |
2173 | if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone ? | 2163 | if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone? |
2174 | return true; | 2164 | return true; |
2175 | } | 2165 | } |
2176 | return false; | 2166 | return false; |
@@ -2213,7 +2203,7 @@ if (!function_exists('json_encode')) { | |||
2213 | } | 2203 | } |
2214 | 2204 | ||
2215 | // Webservices (for use with jQuery/jQueryUI) | 2205 | // Webservices (for use with jQuery/jQueryUI) |
2216 | // eg. index.php?ws=tags&term=minecr | 2206 | // e.g. index.php?ws=tags&term=minecr |
2217 | function processWS() | 2207 | function processWS() |
2218 | { | 2208 | { |
2219 | if (empty($_GET['ws']) || empty($_GET['term'])) return; | 2209 | if (empty($_GET['ws']) || empty($_GET['term'])) return; |
@@ -2221,7 +2211,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). | 2211 | $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'); | 2212 | header('Content-Type: application/json; charset=utf-8'); |
2223 | 2213 | ||
2224 | // Search in tags (case insentitive, cumulative search) | 2214 | // Search in tags (case insensitive, cumulative search) |
2225 | if ($_GET['ws']=='tags') | 2215 | if ($_GET['ws']=='tags') |
2226 | { | 2216 | { |
2227 | $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") | 2217 | $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") |
@@ -2237,7 +2227,7 @@ function processWS() | |||
2237 | exit; | 2227 | exit; |
2238 | } | 2228 | } |
2239 | 2229 | ||
2240 | // Search a single tag (case sentitive, single tag search) | 2230 | // Search a single tag (case sensitive, single tag search) |
2241 | if ($_GET['ws']=='singletag') | 2231 | if ($_GET['ws']=='singletag') |
2242 | { | 2232 | { |
2243 | /* To speed up things, we store list of tags in session */ | 2233 | /* To speed up things, we store list of tags in session */ |
@@ -2253,7 +2243,7 @@ function processWS() | |||
2253 | 2243 | ||
2254 | // Re-write configuration file according to globals. | 2244 | // Re-write configuration file according to globals. |
2255 | // Requires some $GLOBALS to be set (login,hash,salt,title). | 2245 | // 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. | 2246 | // 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.) | 2247 | // (otherwise, the function simply returns.) |
2258 | function writeConfig() | 2248 | function writeConfig() |
2259 | { | 2249 | { |
@@ -2273,12 +2263,12 @@ function writeConfig() | |||
2273 | } | 2263 | } |
2274 | } | 2264 | } |
2275 | 2265 | ||
2276 | /* Because some f*cking services like Flickr require an extra HTTP request to get the thumbnail URL, | 2266 | /* 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. | 2267 | 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. | 2268 | 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: | 2269 | This function is called by passing the URL: |
2280 | http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] | 2270 | http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] |
2281 | [URL] is the URL of the link (eg. a flickr page) | 2271 | [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). | 2272 | [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. | 2273 | The function below will fetch the image from the webservice and store it in the cache. |
2284 | */ | 2274 | */ |
@@ -2286,7 +2276,7 @@ function genThumbnail() | |||
2286 | { | 2276 | { |
2287 | // Make sure the parameters in the URL were generated by us. | 2277 | // Make sure the parameters in the URL were generated by us. |
2288 | $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']); | 2278 | $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']); |
2289 | if ($sign!=$_GET['hmac']) die('Naughty boy !'); | 2279 | if ($sign!=$_GET['hmac']) die('Naughty boy!'); |
2290 | 2280 | ||
2291 | // Let's see if we don't already have the image for this URL in the cache. | 2281 | // Let's see if we don't already have the image for this URL in the cache. |
2292 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; | 2282 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; |
@@ -2311,22 +2301,22 @@ function genThumbnail() | |||
2311 | 2301 | ||
2312 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')) | 2302 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')) |
2313 | { | 2303 | { |
2314 | // Crude replacement to handle new Flickr domain policy (They prefer www. now) | 2304 | // Crude replacement to handle new flickr domain policy (They prefer www. now) |
2315 | $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url); | 2305 | $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url); |
2316 | 2306 | ||
2317 | // Is this a link to an image, or to a flickr page ? | 2307 | // Is this a link to an image, or to a flickr page ? |
2318 | $imageurl=''; | 2308 | $imageurl=''; |
2319 | if (endswith(parse_url($url,PHP_URL_PATH),'.jpg')) | 2309 | 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 | 2310 | { // 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); | 2311 | preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); |
2322 | if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; | 2312 | if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; |
2323 | } | 2313 | } |
2324 | else // this is a flickr page (html) | 2314 | else // This is a flickr page (html) |
2325 | { | 2315 | { |
2326 | list($httpstatus,$headers,$data) = getHTTP($url,20); // Get the flickr html page. | 2316 | list($httpstatus,$headers,$data) = getHTTP($url,20); // Get the flickr html page. |
2327 | if (strpos($httpstatus,'200 OK')!==false) | 2317 | if (strpos($httpstatus,'200 OK')!==false) |
2328 | { | 2318 | { |
2329 | // Flickr now nicely provides the URL of the thumbnail in each flickr page. | 2319 | // flickr now nicely provides the URL of the thumbnail in each flickr page. |
2330 | preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!',$data,$matches); | 2320 | preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!',$data,$matches); |
2331 | if (!empty($matches[1])) $imageurl=$matches[1]; | 2321 | if (!empty($matches[1])) $imageurl=$matches[1]; |
2332 | 2322 | ||
@@ -2357,7 +2347,7 @@ function genThumbnail() | |||
2357 | elseif ($domain=='vimeo.com' ) | 2347 | elseif ($domain=='vimeo.com' ) |
2358 | { | 2348 | { |
2359 | // This is more complex: we have to perform a HTTP request, then parse the result. | 2349 | // 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 | 2350 | // 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); | 2351 | $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); | 2352 | list($httpstatus,$headers,$data) = getHTTP('http://vimeo.com/api/v2/video/'.htmlspecialchars($vid).'.php',5); |
2363 | if (strpos($httpstatus,'200 OK')!==false) | 2353 | if (strpos($httpstatus,'200 OK')!==false) |
@@ -2493,7 +2483,7 @@ function resizeImage($filepath) | |||
2493 | } | 2483 | } |
2494 | 2484 | ||
2495 | // Invalidate caches when the database is changed or the user logs out. | 2485 | // Invalidate caches when the database is changed or the user logs out. |
2496 | // (eg. tags cache). | 2486 | // (e.g. tags cache). |
2497 | function invalidateCaches() | 2487 | function invalidateCaches() |
2498 | { | 2488 | { |
2499 | unset($_SESSION['tags']); // Purge cache attached to session. | 2489 | unset($_SESSION['tags']); // Purge cache attached to session. |