diff options
author | Seb Sauvage <sebsauvage@sebsauvage.net> | 2011-10-13 13:10:10 +0200 |
---|---|---|
committer | Emilien Klein <emilien@klein.st> | 2011-10-13 13:10:10 +0200 |
commit | 008d8b95ef7d7b5e8e79b633ecc6d0097e0b0e28 (patch) | |
tree | 732f5070f50066c9c83a671ed410e71b076071a1 | |
parent | 99c9c9541b012eebdb84ee33a765bb18a62fb0d7 (diff) | |
download | Shaarli-008d8b95ef7d7b5e8e79b633ecc6d0097e0b0e28.tar.gz Shaarli-008d8b95ef7d7b5e8e79b633ecc6d0097e0b0e28.tar.zst Shaarli-008d8b95ef7d7b5e8e79b633ecc6d0097e0b0e28.zip |
Version 0.0.25 beta:
- Changed: Now thumbnails generated by Shaarli are croped to a height of 120 pixels.
- Changed: YouTube thumbnails now use default.jpg instead of 2.jpg (This is usually more pertinent).
- Changed: As per request, configuration options (such as HIDE_TIMESTAMPS, ENABLE_THUMBNAILS, etc.) can now be put in a an external file so that you do not have to tweak them again when you upgrade Shaarli. Just add the file data/options.php.
- Corrected: Shaarli now supports newlines in titles (thanks to dixy).
- Changed: If a single link is displayed, the page title contains the title of the link.
- Changed: Shaarli page title is clickable (and has the same link as “Home”).
- Added: Better CSS for printing (thanks to jerrywham suggestion)
- Changed: A few CSS tweaks (thanks to maethor for suggestion)
- Added: You can now use a redirector or anonymizing proxy for links (such as http://anonym.to/? to mask you HTTP_REFERER). Just go to Tools > Configure > Redirector. (thanks to Accent Grave for the suggestion)
- Added: The option ENABLE_LOCALCACHE can be set to false for those who have a limited quota on their host. This will disable the local thumbnail cache. Services which require the use of the cache will have no thumbnails (vimeo, flickr, direct link to image). Other services will still have a thumbnail (youtube,imgur.com,dailymotion,imageshack.us).
- Corrected: The link to the RSS feed in page header was not correct.
-rw-r--r-- | index.php | 190 | ||||
-rw-r--r-- | shaarli.css | 37 |
2 files changed, 139 insertions, 88 deletions
@@ -1,29 +1,30 @@ | |||
1 | <?php | 1 | <?php |
2 | // Shaarli 0.0.24 beta - Shaare your links... | 2 | // Shaarli 0.0.25 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 | 6 | ||
7 | // Requires: php 5.1.x | 7 | // Requires: php 5.1.x |
8 | 8 | // (but autocomplete fields will only work if you have php 5.2.x) | |
9 | // ----------------------------------------------------------------------------------------------- | 9 | // ----------------------------------------------------------------------------------------------- |
10 | // User config: | 10 | // User config: |
11 | define('DATADIR','data'); // Data subdirectory | 11 | $GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory |
12 | define('CONFIG_FILE',DATADIR.'/config.php'); // Configuration file (user login/password) | 12 | $GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password) |
13 | define('DATASTORE',DATADIR.'/datastore.php'); // Data storage file. | 13 | $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; // Data storage file. |
14 | define('LINKS_PER_PAGE',20); // Default links per page. | 14 | $GLOBALS['config']['LINKS_PER_PAGE'] = 20; // Default links per page. |
15 | define('IPBANS_FILENAME',DATADIR.'/ipbans.php'); // File storage for failures and bans. | 15 | $GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php'; // File storage for failures and bans. |
16 | define('BAN_AFTER',4); // Ban IP after this many failures. | 16 | $GLOBALS['config']['BAN_AFTER'] = 4; // Ban IP after this many failures. |
17 | define('BAN_DURATION',1800); // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes) | 17 | $GLOBALS['config']['BAN_DURATION'] = 1800; // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes) |
18 | define('OPEN_SHAARLI',false); // If true, anyone can add/edit/delete links without having to login | 18 | $GLOBALS['config']['OPEN_SHAARLI'] = false; // If true, anyone can add/edit/delete links without having to login |
19 | define('HIDE_TIMESTAMPS',false); // If true, the moment when links were saved are not shown to users that are not logged in. | 19 | $GLOBALS['config']['HIDE_TIMESTAMPS'] = false; // If true, the moment when links were saved are not shown to users that are not logged in. |
20 | define('ENABLE_THUMBNAILS',true); // Enable thumbnails in links. | 20 | $GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links. |
21 | define('CACHEDIR','cache'); // Cache directory for thumbnails for SLOW services (like flickr) | 21 | $GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr) |
22 | $GLOBALS['config']['ENABLE_LOCALCACHE'] = true; // Enable Shaarli to store thumbnail in a local cache. Disable to reduce webspace usage. | ||
22 | 23 | ||
23 | // ----------------------------------------------------------------------------------------------- | 24 | // ----------------------------------------------------------------------------------------------- |
24 | // Program config (touch at your own risks !) | 25 | // Program config (touch at your own risks !) |
25 | define('UPDATECHECK_FILENAME',DATADIR.'/lastupdatecheck.txt'); // For updates check of Shaarli. | 26 | $GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli. |
26 | define('UPDATECHECK_INTERVAL',86400); // Updates check frequency for Shaarli. 86400 seconds=24 hours | 27 | $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours |
27 | ini_set('max_input_time','60'); // High execution time in case of problematic imports/exports. | 28 | ini_set('max_input_time','60'); // High execution time in case of problematic imports/exports. |
28 | ini_set('memory_limit', '128M'); // Try to set max upload file size and read (May not work on some hosts). | 29 | ini_set('memory_limit', '128M'); // Try to set max upload file size and read (May not work on some hosts). |
29 | ini_set('post_max_size', '16M'); | 30 | ini_set('post_max_size', '16M'); |
@@ -36,6 +37,9 @@ error_reporting(E_ALL^E_WARNING); // See all error except warnings. | |||
36 | //error_reporting(-1); // See all errors (for debugging only) | 37 | //error_reporting(-1); // See all errors (for debugging only) |
37 | ob_start(); | 38 | ob_start(); |
38 | 39 | ||
40 | // Optionnal config file. | ||
41 | if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); | ||
42 | |||
39 | // In case stupid admin has left magic_quotes enabled in php.ini: | 43 | // In case stupid admin has left magic_quotes enabled in php.ini: |
40 | if (get_magic_quotes_gpc()) | 44 | if (get_magic_quotes_gpc()) |
41 | { | 45 | { |
@@ -49,13 +53,16 @@ header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); | |||
49 | header("Cache-Control: no-store, no-cache, must-revalidate"); | 53 | header("Cache-Control: no-store, no-cache, must-revalidate"); |
50 | header("Cache-Control: post-check=0, pre-check=0", false); | 54 | header("Cache-Control: post-check=0, pre-check=0", false); |
51 | header("Pragma: no-cache"); | 55 | header("Pragma: no-cache"); |
52 | define('shaarli_version','0.0.24 beta'); | 56 | define('shaarli_version','0.0.25 beta'); |
53 | if (!is_dir(DATADIR)) { mkdir(DATADIR,0705); chmod(DATADIR,0705); } | 57 | if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } |
54 | if (!is_dir(CACHEDIR)) { mkdir(CACHEDIR,0705); chmod(CACHEDIR,0705); } | 58 | if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. |
55 | if (!is_file(DATADIR.'/.htaccess')) { file_put_contents(DATADIR.'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. | 59 | if ($GLOBALS['config']['ENABLE_LOCALCACHE']) |
56 | if (!is_file(CACHEDIR.'/.htaccess')) { file_put_contents(CACHEDIR.'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. | 60 | { |
57 | if (!is_file(CONFIG_FILE)) install(); | 61 | if (!is_dir($GLOBALS['config']['CACHEDIR'])) { mkdir($GLOBALS['config']['CACHEDIR'],0705); chmod($GLOBALS['config']['CACHEDIR'],0705); } |
58 | require CONFIG_FILE; // Read login/password hash into $GLOBALS. | 62 | if (!is_file($GLOBALS['config']['CACHEDIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['CACHEDIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. |
63 | } | ||
64 | if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); | ||
65 | require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. | ||
59 | // Small protection against dodgy config files: | 66 | // Small protection against dodgy config files: |
60 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(serverUrl().$_SERVER['SCRIPT_NAME']); | 67 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(serverUrl().$_SERVER['SCRIPT_NAME']); |
61 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); | 68 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); |
@@ -83,16 +90,16 @@ function checkUpdate() | |||
83 | if (!isLoggedIn()) return ''; // Do not check versions for visitors. | 90 | if (!isLoggedIn()) return ''; // Do not check versions for visitors. |
84 | 91 | ||
85 | // Get latest version number at most once a day. | 92 | // Get latest version number at most once a day. |
86 | if (!is_file(UPDATECHECK_FILENAME) || (filemtime(UPDATECHECK_FILENAME)<time()-(UPDATECHECK_INTERVAL))) | 93 | if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])<time()-($GLOBALS['config']['UPDATECHECK_INTERVAL']))) |
87 | { | 94 | { |
88 | $version=shaarli_version; | 95 | $version=shaarli_version; |
89 | list($httpstatus,$headers,$data) = getHTTP('http://sebsauvage.net/files/shaarli_version.txt',2); | 96 | list($httpstatus,$headers,$data) = getHTTP('http://sebsauvage.net/files/shaarli_version.txt',2); |
90 | if (strpos($httpstatus,'200 OK')) $version=$data; | 97 | if (strpos($httpstatus,'200 OK')) $version=$data; |
91 | // If failed, nevermind. We don't want to bother the user with that. | 98 | // If failed, nevermind. We don't want to bother the user with that. |
92 | file_put_contents(UPDATECHECK_FILENAME,$version); // touch file date | 99 | file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date |
93 | } | 100 | } |
94 | // Compare versions: | 101 | // Compare versions: |
95 | $newestversion=file_get_contents(UPDATECHECK_FILENAME); | 102 | $newestversion=file_get_contents($GLOBALS['config']['UPDATECHECK_FILENAME']); |
96 | if (version_compare($newestversion,shaarli_version)==1) return $newestversion; | 103 | if (version_compare($newestversion,shaarli_version)==1) return $newestversion; |
97 | return ''; | 104 | return ''; |
98 | } | 105 | } |
@@ -102,7 +109,7 @@ function checkUpdate() | |||
102 | function logm($message) | 109 | function logm($message) |
103 | { | 110 | { |
104 | $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; | 111 | $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; |
105 | file_put_contents(DATADIR.'/log.txt',$t,FILE_APPEND); | 112 | file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt',$t,FILE_APPEND); |
106 | } | 113 | } |
107 | 114 | ||
108 | /* Returns the small hash of a string | 115 | /* Returns the small hash of a string |
@@ -126,7 +133,8 @@ function smallHash($text) | |||
126 | // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 | 133 | // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 |
127 | function text2clickable($url) | 134 | function text2clickable($url) |
128 | { | 135 | { |
129 | return preg_replace('!((?:https?|ftp)://\S+[[:alnum:]]/?)!si','<a href="$1" rel="nofollow">$1</a> ',$url); | 136 | $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']; |
137 | return preg_replace('!((?:https?|ftp)://\S+[[:alnum:]]/?)!si','<a href="'.$redir.'$1" rel="nofollow">$1</a> ',$url); | ||
130 | } | 138 | } |
131 | // ------------------------------------------------------------------------------------------ | 139 | // ------------------------------------------------------------------------------------------ |
132 | // Sniff browser language to display dates in the right format automatically. | 140 | // Sniff browser language to display dates in the right format automatically. |
@@ -180,7 +188,7 @@ function check_auth($login,$password) | |||
180 | // Returns true if the user is logged in. | 188 | // Returns true if the user is logged in. |
181 | function isLoggedIn() | 189 | function isLoggedIn() |
182 | { | 190 | { |
183 | if (OPEN_SHAARLI) return true; | 191 | if ($GLOBALS['config']['OPEN_SHAARLI']) return true; |
184 | 192 | ||
185 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. | 193 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. |
186 | if (empty($_SESSION['uid']) || $_SESSION['ip']!=allIPs() || time()>=$_SESSION['expires_on']) | 194 | if (empty($_SESSION['uid']) || $_SESSION['ip']!=allIPs() || time()>=$_SESSION['expires_on']) |
@@ -201,21 +209,21 @@ function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SES | |||
201 | // ------------------------------------------------------------------------------------------ | 209 | // ------------------------------------------------------------------------------------------ |
202 | // Brute force protection system | 210 | // Brute force protection system |
203 | // Several consecutive failed logins will ban the IP address for 30 minutes. | 211 | // Several consecutive failed logins will ban the IP address for 30 minutes. |
204 | if (!is_file(IPBANS_FILENAME)) file_put_contents(IPBANS_FILENAME, "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>"); | 212 | if (!is_file($GLOBALS['config']['IPBANS_FILENAME'])) file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>"); |
205 | include IPBANS_FILENAME; | 213 | include $GLOBALS['config']['IPBANS_FILENAME']; |
206 | // Signal a failed login. Will ban the IP if too many failures: | 214 | // Signal a failed login. Will ban the IP if too many failures: |
207 | function ban_loginFailed() | 215 | function ban_loginFailed() |
208 | { | 216 | { |
209 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 217 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; |
210 | if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0; | 218 | if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0; |
211 | $gb['FAILURES'][$ip]++; | 219 | $gb['FAILURES'][$ip]++; |
212 | if ($gb['FAILURES'][$ip]>(BAN_AFTER-1)) | 220 | if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1)) |
213 | { | 221 | { |
214 | $gb['BANS'][$ip]=time()+BAN_DURATION; | 222 | $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION']; |
215 | logm('IP address banned from login'); | 223 | logm('IP address banned from login'); |
216 | } | 224 | } |
217 | $GLOBALS['IPBANS'] = $gb; | 225 | $GLOBALS['IPBANS'] = $gb; |
218 | file_put_contents(IPBANS_FILENAME, "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 226 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); |
219 | } | 227 | } |
220 | 228 | ||
221 | // Signals a successful login. Resets failed login counter. | 229 | // Signals a successful login. Resets failed login counter. |
@@ -224,7 +232,7 @@ function ban_loginOk() | |||
224 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 232 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; |
225 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | 233 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); |
226 | $GLOBALS['IPBANS'] = $gb; | 234 | $GLOBALS['IPBANS'] = $gb; |
227 | file_put_contents(IPBANS_FILENAME, "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 235 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); |
228 | } | 236 | } |
229 | 237 | ||
230 | // Checks if the user CAN login. If 'true', the user can try to login. | 238 | // Checks if the user CAN login. If 'true', the user can try to login. |
@@ -238,7 +246,7 @@ function ban_canLogin() | |||
238 | { // Ban expired, user can try to login again. | 246 | { // Ban expired, user can try to login again. |
239 | logm('Ban lifted.'); | 247 | logm('Ban lifted.'); |
240 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | 248 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); |
241 | file_put_contents(IPBANS_FILENAME, "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 249 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); |
242 | return true; // Ban has expired, user can login. | 250 | return true; // Ban has expired, user can login. |
243 | } | 251 | } |
244 | return false; // User is banned. | 252 | return false; // User is banned. |
@@ -420,7 +428,7 @@ function getHTTP($url,$timeout=30) | |||
420 | // (Returns an empty string if not found.) | 428 | // (Returns an empty string if not found.) |
421 | function html_extract_title($html) | 429 | function html_extract_title($html) |
422 | { | 430 | { |
423 | return preg_match('!<title>(.*?)</title>!i', $html, $matches) ? $matches[1] : ''; | 431 | return preg_match('!<title>(.*)</title>!is', $html, $matches) ? trim(str_replace("\n",' ', $matches[1])) : '' ; |
424 | } | 432 | } |
425 | 433 | ||
426 | // ------------------------------------------------------------------------------------------ | 434 | // ------------------------------------------------------------------------------------------ |
@@ -511,14 +519,14 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
511 | // ---- Misc methods | 519 | // ---- Misc methods |
512 | private function checkdb() // Check if db directory and file exists. | 520 | private function checkdb() // Check if db directory and file exists. |
513 | { | 521 | { |
514 | if (!file_exists(DATASTORE)) // Create a dummy database for example. | 522 | if (!file_exists($GLOBALS['config']['DATASTORE'])) // Create a dummy database for example. |
515 | { | 523 | { |
516 | $this->links = array(); | 524 | $this->links = array(); |
517 | $link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','private'=>0,'linkdate'=>'20110914_190000','tags'=>'opensource software'); | 525 | $link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','private'=>0,'linkdate'=>'20110914_190000','tags'=>'opensource software'); |
518 | $this->links[$link['linkdate']] = $link; | 526 | $this->links[$link['linkdate']] = $link; |
519 | $link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://pastebin.com/smCEEeSn','description'=>'SShhhh!! I\'m a private link only YOU can see. You can delete me too.','private'=>1,'linkdate'=>'20110914_074522','tags'=>'secretstuff'); | 527 | $link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://pastebin.com/smCEEeSn','description'=>'SShhhh!! I\'m a private link only YOU can see. You can delete me too.','private'=>1,'linkdate'=>'20110914_074522','tags'=>'secretstuff'); |
520 | $this->links[$link['linkdate']] = $link; | 528 | $this->links[$link['linkdate']] = $link; |
521 | file_put_contents(DATASTORE, PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk | 529 | file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk |
522 | } | 530 | } |
523 | } | 531 | } |
524 | 532 | ||
@@ -526,7 +534,7 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
526 | private function readdb() | 534 | private function readdb() |
527 | { | 535 | { |
528 | // Read data | 536 | // Read data |
529 | $this->links=(file_exists(DATASTORE) ? unserialize(gzinflate(base64_decode(substr(file_get_contents(DATASTORE),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() ); | 537 | $this->links=(file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() ); |
530 | // Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439 | 538 | // Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439 |
531 | 539 | ||
532 | // If user is not logged in, filter private links. | 540 | // If user is not logged in, filter private links. |
@@ -546,7 +554,7 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
546 | public function savedb() | 554 | public function savedb() |
547 | { | 555 | { |
548 | if (!$this->loggedin) die('You are not authorized to change the database.'); | 556 | if (!$this->loggedin) die('You are not authorized to change the database.'); |
549 | file_put_contents(DATASTORE, PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); | 557 | file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); |
550 | } | 558 | } |
551 | 559 | ||
552 | // Returns the link for a given URL (if it exists). false it does not exist. | 560 | // Returns the link for a given URL (if it exists). false it does not exist. |
@@ -644,7 +652,7 @@ function showRSS() | |||
644 | $link = $linksToDisplay[$keys[$i]]; | 652 | $link = $linksToDisplay[$keys[$i]]; |
645 | $rfc822date = linkdate2rfc822($link['linkdate']); | 653 | $rfc822date = linkdate2rfc822($link['linkdate']); |
646 | echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid>'.htmlspecialchars($link['url']).'</guid><link>'.htmlspecialchars($link['url']).'</link>'; | 654 | echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid>'.htmlspecialchars($link['url']).'</guid><link>'.htmlspecialchars($link['url']).'</link>'; |
647 | if (!HIDE_TIMESTAMPS || isLoggedIn()) echo '<pubDate>'.htmlspecialchars($rfc822date).'</pubDate>'; | 655 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo '<pubDate>'.htmlspecialchars($rfc822date).'</pubDate>'; |
648 | echo '<description><![CDATA['.nl2br(htmlspecialchars($link['description'])).']]></description></item>'."\n"; | 656 | echo '<description><![CDATA['.nl2br(htmlspecialchars($link['description'])).']]></description></item>'."\n"; |
649 | $i++; | 657 | $i++; |
650 | } | 658 | } |
@@ -676,13 +684,13 @@ function showATOM() | |||
676 | $iso8601date = linkdate2iso8601($link['linkdate']); | 684 | $iso8601date = linkdate2iso8601($link['linkdate']); |
677 | $latestDate = max($latestDate,$iso8601date); | 685 | $latestDate = max($latestDate,$iso8601date); |
678 | $entries.='<entry><title>'.htmlspecialchars($link['title']).'</title><link href="'.htmlspecialchars($link['url']).'"/><id>'.htmlspecialchars($link['url']).'</id>'; | 686 | $entries.='<entry><title>'.htmlspecialchars($link['title']).'</title><link href="'.htmlspecialchars($link['url']).'"/><id>'.htmlspecialchars($link['url']).'</id>'; |
679 | if (!HIDE_TIMESTAMPS || isLoggedIn()) $entries.='<updated>'.htmlspecialchars($iso8601date).'</updated>'; | 687 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.='<updated>'.htmlspecialchars($iso8601date).'</updated>'; |
680 | $entries.='<summary>'.nl2br(htmlspecialchars($link['description'])).'</summary></entry>'."\n"; | 688 | $entries.='<summary>'.nl2br(htmlspecialchars($link['description'])).'</summary></entry>'."\n"; |
681 | $i++; | 689 | $i++; |
682 | } | 690 | } |
683 | $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">'; | 691 | $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">'; |
684 | $feed.='<title>'.htmlspecialchars($GLOBALS['title']).'</title>'; | 692 | $feed.='<title>'.htmlspecialchars($GLOBALS['title']).'</title>'; |
685 | if (!HIDE_TIMESTAMPS || isLoggedIn()) $feed.='<updated>'.htmlspecialchars($latestDate).'</updated>'; | 693 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.htmlspecialchars($latestDate).'</updated>'; |
686 | $feed.='<link href="'.htmlspecialchars($pageaddr).'" />'; | 694 | $feed.='<link href="'.htmlspecialchars($pageaddr).'" />'; |
687 | $feed.='<author><uri>'.htmlspecialchars($pageaddr).'</uri></author>'; | 695 | $feed.='<author><uri>'.htmlspecialchars($pageaddr).'</uri></author>'; |
688 | $feed.='<id>'.htmlspecialchars($pageaddr).'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. | 696 | $feed.='<id>'.htmlspecialchars($pageaddr).'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. |
@@ -705,7 +713,7 @@ function renderPage() | |||
705 | // -------- Display login form. | 713 | // -------- Display login form. |
706 | if (startswith($_SERVER["QUERY_STRING"],'do=login')) | 714 | if (startswith($_SERVER["QUERY_STRING"],'do=login')) |
707 | { | 715 | { |
708 | if (OPEN_SHAARLI) { header('Location: ?'); exit; } // No need to login for open Shaarli | 716 | if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli |
709 | if (!ban_canLogin()) | 717 | if (!ban_canLogin()) |
710 | { | 718 | { |
711 | $loginform='<div id="headerform">You have been banned from login after too many failed attempts. Try later.</div>'; | 719 | $loginform='<div id="headerform">You have been banned from login after too many failed attempts. Try later.</div>'; |
@@ -820,7 +828,7 @@ HTML; | |||
820 | { | 828 | { |
821 | $pageabsaddr=serverUrl().$_SERVER["SCRIPT_NAME"]; // Why doesn't php have a built-in function for that ? | 829 | $pageabsaddr=serverUrl().$_SERVER["SCRIPT_NAME"]; // Why doesn't php have a built-in function for that ? |
822 | // The javascript code for the bookmarklet: | 830 | // The javascript code for the bookmarklet: |
823 | $changepwd = (OPEN_SHAARLI ? '' : '<a href="?do=changepasswd"><b>Change password</b></a> - Change your password.<br><br>' ); | 831 | $changepwd = ($GLOBALS['config']['OPEN_SHAARLI'] ? '' : '<a href="?do=changepasswd"><b>Change password</b></a> - Change your password.<br><br>' ); |
824 | $toolbar= <<<HTML | 832 | $toolbar= <<<HTML |
825 | <div id="headerform"><br> | 833 | <div id="headerform"><br> |
826 | {$changepwd} | 834 | {$changepwd} |
@@ -839,7 +847,7 @@ HTML; | |||
839 | // -------- User wants to change his/her password. | 847 | // -------- User wants to change his/her password. |
840 | if (startswith($_SERVER["QUERY_STRING"],'do=changepasswd')) | 848 | if (startswith($_SERVER["QUERY_STRING"],'do=changepasswd')) |
841 | { | 849 | { |
842 | if (OPEN_SHAARLI) die('You are not supposed to change a password on an Open Shaarli.'); | 850 | if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.'); |
843 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) | 851 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) |
844 | { | 852 | { |
845 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! | 853 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! |
@@ -882,6 +890,7 @@ HTML; | |||
882 | $tz = $_POST['continent'].'/'.$_POST['city']; | 890 | $tz = $_POST['continent'].'/'.$_POST['city']; |
883 | $GLOBALS['timezone'] = $tz; | 891 | $GLOBALS['timezone'] = $tz; |
884 | $GLOBALS['title']=$_POST['title']; | 892 | $GLOBALS['title']=$_POST['title']; |
893 | $GLOBALS['redirector']=$_POST['redirector']; | ||
885 | writeConfig(); | 894 | writeConfig(); |
886 | echo '<script language="JavaScript">alert("Configuration was saved.");document.location=\'?do=tools\';</script>'; | 895 | echo '<script language="JavaScript">alert("Configuration was saved.");document.location=\'?do=tools\';</script>'; |
887 | exit; | 896 | exit; |
@@ -890,6 +899,7 @@ HTML; | |||
890 | { | 899 | { |
891 | $token = getToken(); | 900 | $token = getToken(); |
892 | $title = htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES); | 901 | $title = htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES); |
902 | $redirector = htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES); | ||
893 | list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); | 903 | list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); |
894 | $timezone_html=''; if ($timezone_form!='') $timezone_html='<tr><td valign="top"><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; | 904 | $timezone_html=''; if ($timezone_form!='') $timezone_html='<tr><td valign="top"><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; |
895 | $changepwdform= <<<HTML | 905 | $changepwdform= <<<HTML |
@@ -897,6 +907,7 @@ ${timezone_js}<form method="POST" action="" name="configform" id="configform"><i | |||
897 | <table border="0" cellpadding="20"> | 907 | <table border="0" cellpadding="20"> |
898 | <tr><td><b>Page title:</b></td><td><input type="text" name="title" id="title" size="50" value="{$title}"></td></tr> | 908 | <tr><td><b>Page title:</b></td><td><input type="text" name="title" id="title" size="50" value="{$title}"></td></tr> |
899 | {$timezone_html} | 909 | {$timezone_html} |
910 | <tr><td valign="top"><b>Redirector</b></td><td><input type="text" name="redirector" id="redirector" size="50" value="{$redirector}"><br>(e.g. <i>http://anonym.to/?</i> will mask the HTTP_REFERER)</td></tr> | ||
900 | <tr><td></td><td align="right"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr> | 911 | <tr><td></td><td align="right"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr> |
901 | </table> | 912 | </table> |
902 | </form> | 913 | </form> |
@@ -1283,13 +1294,13 @@ function templateLinkList() | |||
1283 | if (!empty($_GET['searchterm'])) // Fulltext search | 1294 | if (!empty($_GET['searchterm'])) // Fulltext search |
1284 | { | 1295 | { |
1285 | $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm'])); | 1296 | $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm'])); |
1286 | $searched=' <b>'.count($linksToDisplay).' results for <i>'.htmlspecialchars(trim($_GET['searchterm'])).'</i></b>:'; | 1297 | $searched=count($linksToDisplay).' results for <i>'.htmlspecialchars(trim($_GET['searchterm'])).'</i>:'; |
1287 | } | 1298 | } |
1288 | elseif (!empty($_GET['searchtags'])) // Search by tag | 1299 | elseif (!empty($_GET['searchtags'])) // Search by tag |
1289 | { | 1300 | { |
1290 | $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 1301 | $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
1291 | $tagshtml=''; foreach(explode(' ',trim($_GET['searchtags'])) as $tag) $tagshtml.='<span class="linktag" title="Remove tag"><a href="?removetag='.htmlspecialchars($tag).'">'.htmlspecialchars($tag).' <span style="border-left:1px solid #aaa; padding-left:5px; color:#6767A7;">x</span></a></span> '; | 1302 | $tagshtml=''; foreach(explode(' ',trim($_GET['searchtags'])) as $tag) $tagshtml.='<span class="linktag" title="Remove tag"><a href="?removetag='.htmlspecialchars($tag).'">'.htmlspecialchars($tag).' <span style="border-left:1px solid #aaa; padding-left:5px; color:#6767A7;">x</span></a></span> '; |
1292 | $searched=' <b>'.count($linksToDisplay).' results for tags '.$tagshtml.':</b>'; | 1303 | $searched=''.count($linksToDisplay).' results for tags '.$tagshtml.':'; |
1293 | } | 1304 | } |
1294 | elseif (preg_match('/[a-zA-Z0-9-_@]{6}/',$_SERVER["QUERY_STRING"])) // Detect smallHashes in URL | 1305 | elseif (preg_match('/[a-zA-Z0-9-_@]{6}/',$_SERVER["QUERY_STRING"])) // Detect smallHashes in URL |
1295 | { | 1306 | { |
@@ -1297,7 +1308,7 @@ function templateLinkList() | |||
1297 | } | 1308 | } |
1298 | else | 1309 | else |
1299 | $linksToDisplay = $LINKSDB; // otherwise, display without filtering. | 1310 | $linksToDisplay = $LINKSDB; // otherwise, display without filtering. |
1300 | 1311 | if ($searched!='') $searched='<div id="searchcriteria">'.$searched.'</div>'; | |
1301 | $linklist=''; | 1312 | $linklist=''; |
1302 | $actions=''; | 1313 | $actions=''; |
1303 | 1314 | ||
@@ -1307,13 +1318,19 @@ function templateLinkList() | |||
1307 | If my class implements ArrayAccess, why won't array_keys() accept it ? ( $keys=array_keys($linksToDisplay); ) | 1318 | If my class implements ArrayAccess, why won't array_keys() accept it ? ( $keys=array_keys($linksToDisplay); ) |
1308 | */ | 1319 | */ |
1309 | $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks php. | 1320 | $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks php. |
1321 | |||
1322 | // If there is only a single link, we change on-the-fly the title of the page. | ||
1323 | if (count($linksToDisplay)==1) $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; | ||
1324 | |||
1310 | $pagecount = ceil(count($keys)/$_SESSION['LINKS_PER_PAGE']); | 1325 | $pagecount = ceil(count($keys)/$_SESSION['LINKS_PER_PAGE']); |
1311 | $pagecount = ($pagecount==0 ? 1 : $pagecount); | 1326 | $pagecount = ($pagecount==0 ? 1 : $pagecount); |
1312 | $page=( empty($_GET['page']) ? 1 : intval($_GET['page'])); | 1327 | $page=( empty($_GET['page']) ? 1 : intval($_GET['page'])); |
1313 | $page = ( $page<1 ? 1 : $page ); | 1328 | $page = ( $page<1 ? 1 : $page ); |
1314 | $page = ( $page>$pagecount ? $pagecount : $page ); | 1329 | $page = ( $page>$pagecount ? $pagecount : $page ); |
1315 | $i = ($page-1)*$_SESSION['LINKS_PER_PAGE']; // Start index. | 1330 | $i = ($page-1)*$_SESSION['LINKS_PER_PAGE']; // Start index. |
1316 | $end = $i+$_SESSION['LINKS_PER_PAGE']; | 1331 | $end = $i+$_SESSION['LINKS_PER_PAGE']; |
1332 | $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']; // optional redirector URL | ||
1333 | |||
1317 | while ($i<$end && $i<count($keys)) | 1334 | while ($i<$end && $i<count($keys)) |
1318 | { | 1335 | { |
1319 | $link = $linksToDisplay[$keys[$i]]; | 1336 | $link = $linksToDisplay[$keys[$i]]; |
@@ -1322,11 +1339,15 @@ function templateLinkList() | |||
1322 | $classprivate = ($link['private']==0 ? '' : 'class="private"'); | 1339 | $classprivate = ($link['private']==0 ? '' : 'class="private"'); |
1323 | if (isLoggedIn()) $actions=' <form method="GET" class="buttoneditform"><input type="hidden" name="edit_link" value="'.$link['linkdate'].'"><input type="submit" value="Edit" class="smallbutton"></form>'; | 1340 | if (isLoggedIn()) $actions=' <form method="GET" class="buttoneditform"><input type="hidden" name="edit_link" value="'.$link['linkdate'].'"><input type="submit" value="Edit" class="smallbutton"></form>'; |
1324 | $tags=''; | 1341 | $tags=''; |
1325 | if ($link['tags']!='') foreach(explode(' ',$link['tags']) as $tag) { $tags.='<span class="linktag" title="Add tag"><a href="?addtag='.htmlspecialchars($tag).'">'.htmlspecialchars($tag).'</a></span> '; } | 1342 | if ($link['tags']!='') |
1343 | { | ||
1344 | foreach(explode(' ',$link['tags']) as $tag) { $tags.='<span class="linktag" title="Add tag"><a href="?addtag='.htmlspecialchars($tag).'">'.htmlspecialchars($tag).'</a></span> '; } | ||
1345 | $tags='<div class="linktaglist">'.$tags.'</div>'; | ||
1346 | } | ||
1326 | $linklist.='<li '.$classprivate.'>'.thumbnail($link['url']); | 1347 | $linklist.='<li '.$classprivate.'>'.thumbnail($link['url']); |
1327 | $linklist.='<div class="linkcontainer"><span class="linktitle"><a href="'.htmlspecialchars($link['url']).'">'.htmlspecialchars($title).'</a></span>'.$actions.'<br>'; | 1348 | $linklist.='<div class="linkcontainer"><span class="linktitle"><a href="'.$redir.htmlspecialchars($link['url']).'">'.htmlspecialchars($title).'</a></span>'.$actions.'<br>'; |
1328 | if ($description!='') $linklist.='<div class="linkdescription">'.nl2br($description).'</div><br>'; | 1349 | if ($description!='') $linklist.='<div class="linkdescription">'.nl2br($description).'</div><br>'; |
1329 | if (!HIDE_TIMESTAMPS || isLoggedIn()) $linklist.='<span class="linkdate" title="Short link here"><a href="?'.smallHash($link['linkdate']).'">'.htmlspecialchars(linkdate2locale($link['linkdate'])).' </a> - </span>'; | 1350 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $linklist.='<span class="linkdate" title="Short link here"><a href="?'.smallHash($link['linkdate']).'">'.htmlspecialchars(linkdate2locale($link['linkdate'])).' </a> - </span>'; |
1330 | else $linklist.='<span class="linkdate" title="Short link here"><a href="?'.smallHash($link['linkdate']).'">link</a> - </span>'; | 1351 | else $linklist.='<span class="linkdate" title="Short link here"><a href="?'.smallHash($link['linkdate']).'">link</a> - </span>'; |
1331 | $linklist.='<span class="linkurl" title="Short link">'.htmlspecialchars($link['url']).'</span><br>'.$tags."</div></li>\n"; | 1352 | $linklist.='<span class="linkurl" title="Short link">'.htmlspecialchars($link['url']).'</span><br>'.$tags."</div></li>\n"; |
1332 | $i++; | 1353 | $i++; |
@@ -1353,16 +1374,16 @@ HTML; | |||
1353 | // Understands various services (youtube.com...) | 1374 | // Understands various services (youtube.com...) |
1354 | function thumbnail($url) | 1375 | function thumbnail($url) |
1355 | { | 1376 | { |
1356 | if (!ENABLE_THUMBNAILS) return ''; | 1377 | if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return ''; |
1357 | 1378 | ||
1358 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. | 1379 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. |
1359 | // (eg. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/2.jpg ) | 1380 | // (eg. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg ) |
1360 | // ^^^^^^^^^^^ ^^^^^^^^^^^ | 1381 | // ^^^^^^^^^^^ ^^^^^^^^^^^ |
1361 | $domain = parse_url($url,PHP_URL_HOST); | 1382 | $domain = parse_url($url,PHP_URL_HOST); |
1362 | if ($domain=='youtube.com' || $domain=='www.youtube.com') | 1383 | if ($domain=='youtube.com' || $domain=='www.youtube.com') |
1363 | { | 1384 | { |
1364 | parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail | 1385 | parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail |
1365 | if (!empty($params['v'])) return '<div class="thumbnail"><a href="'.htmlspecialchars($url).'"><img src="http://img.youtube.com/vi/'.htmlspecialchars($params['v']).'/2.jpg" width="120" height="90"></a></div>'; | 1386 | if (!empty($params['v'])) return '<div class="thumbnail"><a href="'.htmlspecialchars($url).'"><img src="http://img.youtube.com/vi/'.htmlspecialchars($params['v']).'/default.jpg" width="120" height="90"></a></div>'; |
1366 | } | 1387 | } |
1367 | if ($domain=='imgur.com') | 1388 | if ($domain=='imgur.com') |
1368 | { | 1389 | { |
@@ -1393,9 +1414,13 @@ function thumbnail($url) | |||
1393 | } | 1414 | } |
1394 | } | 1415 | } |
1395 | 1416 | ||
1417 | |||
1396 | // Some other hosts are SLOW AS HELL and usually require an extra HTTP request to get the thumbnail URL. | 1418 | // Some other hosts are SLOW AS HELL and usually require an extra HTTP request to get the thumbnail URL. |
1397 | // So we deport the thumbnail generation in order not to slow down page generation | 1419 | // So we deport the thumbnail generation in order not to slow down page generation |
1398 | // (and we also cache the thumbnail) | 1420 | // (and we also cache the thumbnail) |
1421 | |||
1422 | if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return ''; // If local cache is disabled, no thumbnails for services which require the use a local cache. | ||
1423 | |||
1399 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') || $domain=='vimeo.com') | 1424 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') || $domain=='vimeo.com') |
1400 | { | 1425 | { |
1401 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) | 1426 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) |
@@ -1432,7 +1457,7 @@ function templatePage($data) | |||
1432 | if ($newversion!='') $newversion='<div id="newversion"><span style="text-decoration:blink;">●</span> Shaarli '.htmlspecialchars($newversion).' is <a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli#download">available</a>.</div>'; | 1457 | if ($newversion!='') $newversion='<div id="newversion"><span style="text-decoration:blink;">●</span> Shaarli '.htmlspecialchars($newversion).' is <a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli#download">available</a>.</div>'; |
1433 | $linkcount = count($LINKSDB); | 1458 | $linkcount = count($LINKSDB); |
1434 | $open=''; | 1459 | $open=''; |
1435 | if (OPEN_SHAARLI) | 1460 | if ($GLOBALS['config']['OPEN_SHAARLI']) |
1436 | { | 1461 | { |
1437 | $menu=' <a href="?do=tools">Tools</a> <a href="?do=addlink"><b>Add link</b></a>'; | 1462 | $menu=' <a href="?do=tools">Tools</a> <a href="?do=addlink"><b>Add link</b></a>'; |
1438 | $open='Open '; | 1463 | $open='Open '; |
@@ -1445,10 +1470,10 @@ function templatePage($data) | |||
1445 | if (!array_key_exists($k,$data)) $data[$k]=''; | 1470 | if (!array_key_exists($k,$data)) $data[$k]=''; |
1446 | } | 1471 | } |
1447 | $jsincludes=''; $jsincludes_bottom = ''; | 1472 | $jsincludes=''; $jsincludes_bottom = ''; |
1448 | if (OPEN_SHAARLI || isLoggedIn()) | 1473 | if ($GLOBALS['config']['OPEN_SHAARLI'] || isLoggedIn()) |
1449 | { | 1474 | { |
1450 | $jsincludes='<script language="JavaScript" src="jquery.min.js"></script><script language="JavaScript" src="jquery-ui.custom.min.js"></script>'; | ||
1451 | $source = serverUrl().$_SERVER['SCRIPT_NAME']; | 1475 | $source = serverUrl().$_SERVER['SCRIPT_NAME']; |
1476 | $jsincludes='<script language="JavaScript" src="jquery.min.js"></script><script language="JavaScript" src="jquery-ui.custom.min.js"></script>'; | ||
1452 | $jsincludes_bottom = <<<JS | 1477 | $jsincludes_bottom = <<<JS |
1453 | <script language="JavaScript"> | 1478 | <script language="JavaScript"> |
1454 | $(document).ready(function() | 1479 | $(document).ready(function() |
@@ -1464,20 +1489,23 @@ JS; | |||
1464 | $feedsearch=''; | 1489 | $feedsearch=''; |
1465 | if (!empty($_GET['searchtags'])) $feedsearch.='&searchtags='.$_GET['searchtags']; | 1490 | if (!empty($_GET['searchtags'])) $feedsearch.='&searchtags='.$_GET['searchtags']; |
1466 | elseif (!empty($_GET['searchterm'])) $feedsearch.='&searchterm='.$_GET['searchterm']; | 1491 | elseif (!empty($_GET['searchterm'])) $feedsearch.='&searchterm='.$_GET['searchterm']; |
1492 | $filtered_feed= ($feedsearch=='' ? '' : 'Filtered '); | ||
1467 | $version=shaarli_version; | 1493 | $version=shaarli_version; |
1468 | 1494 | ||
1469 | $title = htmlspecialchars( $GLOBALS['title'] ); | 1495 | $title = htmlspecialchars( $GLOBALS['title'] ); |
1496 | $pagetitle = htmlspecialchars( empty($GLOBALS['pagetitle']) ? $title : $GLOBALS['pagetitle'] ); | ||
1470 | echo <<<HTML | 1497 | echo <<<HTML |
1471 | <html> | 1498 | <html> |
1472 | <head> | 1499 | <head> |
1473 | <title>{$title}</title> | 1500 | <title>{$pagetitle}</title> |
1474 | <link rel="alternate" type="application/rss+xml" href="{$feedurl}" /> | 1501 | <link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$feedsearch}" title="{$filtered_feed}RSS Feed" /> |
1502 | <link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$feedsearch}" title="{$filtered_feed}ATOM Feed" /> | ||
1475 | <link type="text/css" rel="stylesheet" href="shaarli.css?version={$version}" /> | 1503 | <link type="text/css" rel="stylesheet" href="shaarli.css?version={$version}" /> |
1476 | {$jsincludes} | 1504 | {$jsincludes} |
1477 | </head> | 1505 | </head> |
1478 | <body {$data['onload']}>{$newversion} | 1506 | <body {$data['onload']}>{$newversion} |
1479 | <div id="pageheader"><div style="float:right; font-style:italic; color:#bbb; text-align:right; padding:0 5 0 0;">Shaare your links...<br>{$linkcount} links</div> | 1507 | <div id="pageheader"><div style="float:right; font-style:italic; color:#bbb; text-align:right; padding:0 5 0 0;">Shaare your links...<br>{$linkcount} links</div> |
1480 | <b><i>{$title}</i></b> - <a href="?">Home</a> {$menu} <a href="{$feedurl}?do=rss{$feedsearch}" style="padding-left:30px;">RSS Feed</a> <a href="{$feedurl}?do=atom{$feedsearch}" style="padding-left:10px;">ATOM Feed</a> | 1508 | <span id="shaarli_title"><a href="?">{$title}</a></span> - <a href="?">Home</a> {$menu} <a href="{$feedurl}?do=rss{$feedsearch}" style="padding-left:30px;">RSS Feed</a> <a href="{$feedurl}?do=atom{$feedsearch}" style="padding-left:10px;">ATOM Feed</a> |
1481 | <a href="?do=tagcloud">Tag cloud</a> | 1509 | <a href="?do=tagcloud">Tag cloud</a> |
1482 | {$data['pageheader']} | 1510 | {$data['pageheader']} |
1483 | </div> | 1511 | </div> |
@@ -1617,7 +1645,7 @@ function processWS() | |||
1617 | if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); | 1645 | if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); |
1618 | foreach($_SESSION['tags'] as $key=>$value) | 1646 | foreach($_SESSION['tags'] as $key=>$value) |
1619 | { | 1647 | { |
1620 | if (startsWith($key,$last,$case=false) && !in_array($key,$tags)) $suggested[$addtags.$key.' ']=0;//FIXME | 1648 | if (startsWith($key,$last,$case=false) && !in_array($key,$tags)) $suggested[$addtags.$key.' ']=0; |
1621 | } | 1649 | } |
1622 | echo json_encode(array_keys($suggested)); | 1650 | echo json_encode(array_keys($suggested)); |
1623 | exit; | 1651 | exit; |
@@ -1643,10 +1671,13 @@ function processWS() | |||
1643 | // (otherwise, the function simply returns.) | 1671 | // (otherwise, the function simply returns.) |
1644 | function writeConfig() | 1672 | function writeConfig() |
1645 | { | 1673 | { |
1646 | if (is_file(CONFIG_FILE) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. | 1674 | if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. |
1675 | if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; | ||
1647 | $config='<?php $GLOBALS[\'login\']='.var_export($GLOBALS['login'],true).'; $GLOBALS[\'hash\']='.var_export($GLOBALS['hash'],true).'; $GLOBALS[\'salt\']='.var_export($GLOBALS['salt'],true).'; '; | 1676 | $config='<?php $GLOBALS[\'login\']='.var_export($GLOBALS['login'],true).'; $GLOBALS[\'hash\']='.var_export($GLOBALS['hash'],true).'; $GLOBALS[\'salt\']='.var_export($GLOBALS['salt'],true).'; '; |
1648 | $config .='$GLOBALS[\'timezone\']='.var_export($GLOBALS['timezone'],true).'; date_default_timezone_set('.var_export($GLOBALS['timezone'],true).'); $GLOBALS[\'title\']='.var_export($GLOBALS['title'],true).'; ?>'; | 1677 | $config .='$GLOBALS[\'timezone\']='.var_export($GLOBALS['timezone'],true).'; date_default_timezone_set('.var_export($GLOBALS['timezone'],true).'); $GLOBALS[\'title\']='.var_export($GLOBALS['title'],true).';'; |
1649 | if (!file_put_contents(CONFIG_FILE,$config) || strcmp(file_get_contents(CONFIG_FILE),$config)!=0) | 1678 | $config .= '$GLOBALS[\'redirector\']='.var_export($GLOBALS['redirector'],true).'; '; |
1679 | $config .= ' ?>'; | ||
1680 | if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0) | ||
1650 | { | 1681 | { |
1651 | echo '<script language="JavaScript">alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';</script>'; | 1682 | echo '<script language="JavaScript">alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';</script>'; |
1652 | exit; | 1683 | exit; |
@@ -1670,18 +1701,18 @@ function genThumbnail() | |||
1670 | 1701 | ||
1671 | // Let's see if we don't already have the image for this URL in the cache. | 1702 | // Let's see if we don't already have the image for this URL in the cache. |
1672 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; | 1703 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; |
1673 | if (is_file(CACHEDIR.'/'.$thumbname)) | 1704 | if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$thumbname)) |
1674 | { // We have the thumbnail, just serve it: | 1705 | { // We have the thumbnail, just serve it: |
1675 | header('Content-Type: image/jpeg'); | 1706 | header('Content-Type: image/jpeg'); |
1676 | echo file_get_contents(CACHEDIR.'/'.$thumbname); | 1707 | echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname); |
1677 | return; | 1708 | return; |
1678 | } | 1709 | } |
1679 | // We may also serve a blank image (if service did not respond) | 1710 | // We may also serve a blank image (if service did not respond) |
1680 | $blankname=hash('sha1',$_GET['url']).'.gif'; | 1711 | $blankname=hash('sha1',$_GET['url']).'.gif'; |
1681 | if (is_file(CACHEDIR.'/'.$blankname)) | 1712 | if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$blankname)) |
1682 | { | 1713 | { |
1683 | header('Content-Type: image/gif'); | 1714 | header('Content-Type: image/gif'); |
1684 | echo file_get_contents(CACHEDIR.'/'.$blankname); | 1715 | echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname); |
1685 | return; | 1716 | return; |
1686 | } | 1717 | } |
1687 | 1718 | ||
@@ -1721,7 +1752,7 @@ function genThumbnail() | |||
1721 | list($httpstatus,$headers,$data) = getHTTP($imageurl,10); // Image is 240x120, so 10 seconds to download should be enough. | 1752 | list($httpstatus,$headers,$data) = getHTTP($imageurl,10); // Image is 240x120, so 10 seconds to download should be enough. |
1722 | if (strpos($httpstatus,'200 OK')) | 1753 | if (strpos($httpstatus,'200 OK')) |
1723 | { | 1754 | { |
1724 | file_put_contents(CACHEDIR.'/'.$thumbname,$data); // Save image to cache. | 1755 | file_put_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname,$data); // Save image to cache. |
1725 | header('Content-Type: image/jpeg'); | 1756 | header('Content-Type: image/jpeg'); |
1726 | echo $data; | 1757 | echo $data; |
1727 | return; | 1758 | return; |
@@ -1743,7 +1774,7 @@ function genThumbnail() | |||
1743 | list($httpstatus,$headers,$data) = getHTTP($imageurl,10); | 1774 | list($httpstatus,$headers,$data) = getHTTP($imageurl,10); |
1744 | if (strpos($httpstatus,'200 OK')) | 1775 | if (strpos($httpstatus,'200 OK')) |
1745 | { | 1776 | { |
1746 | file_put_contents(CACHEDIR.'/'.$thumbname,$data); // Save image to cache. | 1777 | file_put_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname,$data); // Save image to cache. |
1747 | header('Content-Type: image/jpeg'); | 1778 | header('Content-Type: image/jpeg'); |
1748 | echo $data; | 1779 | echo $data; |
1749 | return; | 1780 | return; |
@@ -1755,7 +1786,7 @@ function genThumbnail() | |||
1755 | list($httpstatus,$headers,$data) = getHTTP($url,30); // We allow 30 seconds max to download (and downloads are limited to 4 Mb) | 1786 | list($httpstatus,$headers,$data) = getHTTP($url,30); // We allow 30 seconds max to download (and downloads are limited to 4 Mb) |
1756 | if (strpos($httpstatus,'200 OK')) | 1787 | if (strpos($httpstatus,'200 OK')) |
1757 | { | 1788 | { |
1758 | $filepath=CACHEDIR.'/'.$thumbname; | 1789 | $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; |
1759 | file_put_contents($filepath,$data); // Save image to cache. | 1790 | file_put_contents($filepath,$data); // Save image to cache. |
1760 | if (resizeImage($filepath)) | 1791 | if (resizeImage($filepath)) |
1761 | { | 1792 | { |
@@ -1765,9 +1796,10 @@ function genThumbnail() | |||
1765 | } | 1796 | } |
1766 | } | 1797 | } |
1767 | 1798 | ||
1799 | |||
1768 | // Otherwise, return an empty image (8x8 transparent gif) | 1800 | // Otherwise, return an empty image (8x8 transparent gif) |
1769 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); | 1801 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); |
1770 | file_put_contents(CACHEDIR.'/'.$blankname,$blankgif); // Also put something in cache so that this URL is not requested twice. | 1802 | file_put_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname,$blankgif); // Also put something in cache so that this URL is not requested twice. |
1771 | header('Content-Type: image/gif'); | 1803 | header('Content-Type: image/gif'); |
1772 | echo $blankgif; | 1804 | echo $blankgif; |
1773 | } | 1805 | } |
@@ -1788,11 +1820,13 @@ function resizeImage($filepath) | |||
1788 | if (!$im) return false; // Unable to open image (corrupted or not an image) | 1820 | if (!$im) return false; // Unable to open image (corrupted or not an image) |
1789 | $w = imagesx($im); | 1821 | $w = imagesx($im); |
1790 | $h = imagesy($im); | 1822 | $h = imagesy($im); |
1823 | $ystart = 0; $yheight=$h; | ||
1824 | if ($h>$w) { $ystart= ($h/2)-($w/2); $yheight=$w/2; } | ||
1791 | $nw = 120; // Desired width | 1825 | $nw = 120; // Desired width |
1792 | $nh = floor(($h*$nw)/$w); // Compute new width/height while keeping ratio | 1826 | $nh = min(floor(($h*$nw)/$w),120); // Compute new width/height, but maximum 120 pixels height. |
1793 | // Resize image: | 1827 | // Resize image: |
1794 | $im2 = imagecreatetruecolor($nw,$nh); | 1828 | $im2 = imagecreatetruecolor($nw,$nh); |
1795 | imagecopyresampled($im2, $im, 0, 0, 0, 0, $nw, $nh, $w, $h); | 1829 | imagecopyresampled($im2, $im, 0, 0, 0, $ystart, $nw, $nh, $w, $yheight); |
1796 | imageinterlace($im2,true); // For progressive JPEG. | 1830 | imageinterlace($im2,true); // For progressive JPEG. |
1797 | $tempname=$filepath.'_TEMP.jpg'; | 1831 | $tempname=$filepath.'_TEMP.jpg'; |
1798 | imagejpeg($im2, $tempname, 90); | 1832 | imagejpeg($im2, $tempname, 90); |
@@ -1810,9 +1844,9 @@ function invalidateCaches() | |||
1810 | } | 1844 | } |
1811 | 1845 | ||
1812 | if (startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. | 1846 | if (startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. |
1813 | $LINKSDB=new linkdb(isLoggedIn() || OPEN_SHAARLI); // Read links from database (and filter private links if used it not logged in). | 1847 | $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). |
1814 | if (startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI) | 1848 | if (startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI) |
1815 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=LINKS_PER_PAGE; | 1849 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; |
1816 | if (startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } | 1850 | if (startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } |
1817 | if (startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } | 1851 | if (startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } |
1818 | renderPage(); | 1852 | renderPage(); |
diff --git a/shaarli.css b/shaarli.css index a3b9434b..320c7a43 100644 --- a/shaarli.css +++ b/shaarli.css | |||
@@ -33,10 +33,13 @@ filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#6A6A6A', EndC | |||
33 | padding: 0 10 5 10; | 33 | padding: 0 10 5 10; |
34 | margin: auto; | 34 | margin: auto; |
35 | } | 35 | } |
36 | #shaarli_title { font-weight:bold; font-style:italic; } | ||
37 | #shaarli_title a { color: #fff !important; } | ||
36 | #pageheader a:link { color:#bbb; text-decoration:none;} | 38 | #pageheader a:link { color:#bbb; text-decoration:none;} |
37 | #pageheader a:visited { color:#bbb; text-decoration:none;} | 39 | #pageheader a:visited { color:#bbb; text-decoration:none;} |
38 | #pageheader a:hover { color:#FFFFC9; text-decoration:none;} | 40 | #pageheader a:hover { color:#FFFFC9; text-decoration:none;} |
39 | #pageheader a:active { color:#bbb; text-decoration:none;} | 41 | #pageheader a:active { color:#bbb; text-decoration:none;} |
42 | #searchcriteria { padding: 4 0 5 5; font-weight:bold;} | ||
40 | .paging { background-color:#777; color:#ccc; text-align:center; padding:0 0 3 0; clear:both;} | 43 | .paging { background-color:#777; color:#ccc; text-align:center; padding:0 0 3 0; clear:both;} |
41 | .paging a:link { color:#ccc; text-decoration:none;} | 44 | .paging a:link { color:#ccc; text-decoration:none;} |
42 | .paging a:visited { color:#ccc; } | 45 | .paging a:visited { color:#ccc; } |
@@ -47,17 +50,20 @@ margin: auto; | |||
47 | #linklist li { padding:4 10 8 20; border-top: 1px solid #bbb; clear:both; } | 50 | #linklist li { padding:4 10 8 20; border-top: 1px solid #bbb; clear:both; } |
48 | #linklist li.private { background-color: #ccc; border-left:8px solid #888; } | 51 | #linklist li.private { background-color: #ccc; border-left:8px solid #888; } |
49 | .linktitle { font-size:14pt; font-weight:bold; } | 52 | .linktitle { font-size:14pt; font-weight:bold; } |
50 | .linktitle a { text-decoration: none; color:#0000EE; } | 53 | .linktitle a { text-decoration: none; color:#3465A4; } |
51 | .linktitle a:hover { text-decoration: underline; } | 54 | .linktitle a:hover { color:#F57900; } |
52 | .linktitle a:visited { color:#0000BB; } | ||
53 | .linkdate { font-size:8pt; color:#888; } | 55 | .linkdate { font-size:8pt; color:#888; } |
54 | .linkdate a { text-decoration: none; color:#888; } | 56 | .linkdate a { text-decoration: none; color:#888; } |
55 | .linkdate a:hover { text-decoration: underline; } | 57 | .linkdate a:hover { color: #F57900 } |
56 | .linkurl { font-size:8pt; color:#4BAA74; } | 58 | .linkurl { font-size:8pt; color:#4BAA74; } |
57 | .linkdescription { color:#000; margin-top:0px; margin-bottom:0px; font-weight:normal; } | 59 | .linkdescription { color:#000; margin-top:0px; margin-bottom:0px; font-weight:normal; } |
60 | .linkdescription a { text-decoration: none; color:#3465A4; } | ||
61 | .linkdescription a:hover { color:#F57900; } | ||
62 | .linktaglist { } | ||
58 | .linktag { font-size:9pt; color:#777; background-color:#ddd; padding:0 6 0 6; -moz-box-shadow: inset 2px 2px 3px #ffffff; -webkit-box-shadow: inset 2px 2px 3px #ffffff; box-shadow: inset 2px 2px 3px ffffff; | 63 | .linktag { font-size:9pt; color:#777; background-color:#ddd; padding:0 6 0 6; -moz-box-shadow: inset 2px 2px 3px #ffffff; -webkit-box-shadow: inset 2px 2px 3px #ffffff; box-shadow: inset 2px 2px 3px ffffff; |
59 | border-bottom:1px solid #aaa; border-right:1px solid #aaa; } | 64 | border-bottom:1px solid #aaa; border-right:1px solid #aaa; border-radius: 0.3em; } |
60 | .linktag a { color:#777; text-decoration:none; } | 65 | .linktag:hover { border-color: #555573; color:#000; } |
66 | .linktag a { color:#777; text-decoration:none; } | ||
61 | .linkshort { font-size:8pt; color:#888; } | 67 | .linkshort { font-size:8pt; color:#888; } |
62 | .linkshort a { text-decoration: none; color:#393964; } | 68 | .linkshort a { text-decoration: none; color:#393964; } |
63 | .linkshort a:hover { text-decoration: underline; } | 69 | .linkshort a:hover { text-decoration: underline; } |
@@ -68,16 +74,27 @@ border-bottom:1px solid #aaa; border-right:1px solid #aaa; } | |||
68 | #cloudtag a { color:black; text-decoration:none; } | 74 | #cloudtag a { color:black; text-decoration:none; } |
69 | #installform td { font-size: 10pt; padding:10 5 10 5; } | 75 | #installform td { font-size: 10pt; padding:10 5 10 5; } |
70 | #configform td { color:#ccc; font-size: 10pt; padding:10 5 10 5; } | 76 | #configform td { color:#ccc; font-size: 10pt; padding:10 5 10 5; } |
71 | .thumbnail { float:right; margin-left: 10px; } | 77 | .thumbnail { float:right; margin-left: 10px; } |
72 | 78 | /* If you want thumbnails on the left: | |
73 | /* If you want thumbnails on the right: | ||
74 | .thumbnail { float:left; margin-right: 10px; } | 79 | .thumbnail { float:left; margin-right: 10px; } |
75 | .linkcontainer { position: static; margin-left:130px; } | 80 | .linkcontainer { position: static; margin-left:130px; } |
76 | */ | 81 | */ |
77 | 82 | ||
78 | |||
79 | /* Minimal customisation for jQuery widgets */ | 83 | /* Minimal customisation for jQuery widgets */ |
80 | .ui-autocomplete { background-color:#fff; padding-left:5px;} | 84 | .ui-autocomplete { background-color:#fff; padding-left:5px;} |
81 | .ui-state-hover { background-color: #604dff; color:#fff; } | 85 | .ui-state-hover { background-color: #604dff; color:#fff; } |
82 | 86 | ||
87 | @media print { | ||
88 | html {border:none;background:#fff!important;color:#000!important;} | ||
89 | body {font-size:12pt;width:auto!important;margin:auto!important;} | ||
90 | p {orphans:3; /*pas de ligne seule en bas */widows:3;/*pas de ligne seule en haut*/} | ||
91 | a {color:#000!important;text-decoration:none!important;} | ||
92 | #pageheader, .paging, #linklist li form, #footer {display:none;} | ||
93 | #linklist li { padding:2 0 10 0; border-top: 2px solid #000; clear:both; } | ||
94 | #linklist li.private { background-color: none; border-left:0; } | ||
95 | .linkdate { line-height:2; } | ||
96 | .linkurl { color:#000; } | ||
97 | .linkdescription { font-size:10pt;} | ||
98 | .linktag { border: 1px solid black; font-style:italic; font-size:8pt;} | ||
99 | |||
83 | } \ No newline at end of file | 100 | } \ No newline at end of file |