diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 962 |
1 files changed, 461 insertions, 501 deletions
@@ -1,8 +1,8 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | 2 | /** |
3 | * Shaarli v0.7.0 - Shaare your links... | 3 | * Shaarli v0.8.4 - Shaare your links... |
4 | * | 4 | * |
5 | * The personal, minimalist, super-fast, no-database Delicious clone. | 5 | * The personal, minimalist, super-fast, database free, bookmarking service. |
6 | * | 6 | * |
7 | * Friendly fork by the Shaarli community: | 7 | * Friendly fork by the Shaarli community: |
8 | * - https://github.com/shaarli/Shaarli | 8 | * - https://github.com/shaarli/Shaarli |
@@ -22,114 +22,13 @@ if (date_default_timezone_get() == '') { | |||
22 | date_default_timezone_set('UTC'); | 22 | date_default_timezone_set('UTC'); |
23 | } | 23 | } |
24 | 24 | ||
25 | /* ----------------------------------------------------------------------------- | ||
26 | * Hardcoded parameters | ||
27 | * You should not touch any code below (or at your own risks!) | ||
28 | * (These parameters can be overwritten by editing the file /data/config.php) | ||
29 | * ----------------------------------------------------------------------------- | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * Shaarli directories & configuration files | ||
34 | */ | ||
35 | // Data subdirectory | ||
36 | $GLOBALS['config']['DATADIR'] = 'data'; | ||
37 | |||
38 | // Main configuration file | ||
39 | $GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; | ||
40 | |||
41 | // Link datastore | ||
42 | $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; | ||
43 | |||
44 | // Banned IPs | ||
45 | $GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php'; | ||
46 | |||
47 | // Processed updates file. | ||
48 | $GLOBALS['config']['UPDATES_FILE'] = $GLOBALS['config']['DATADIR'].'/updates.txt'; | ||
49 | |||
50 | // Access log | ||
51 | $GLOBALS['config']['LOG_FILE'] = $GLOBALS['config']['DATADIR'].'/log.txt'; | ||
52 | |||
53 | // For updates check of Shaarli | ||
54 | $GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; | ||
55 | |||
56 | // Set ENABLE_UPDATECHECK to disabled by default. | ||
57 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = false; | ||
58 | |||
59 | // RainTPL cache directory (keep the trailing slash!) | ||
60 | $GLOBALS['config']['RAINTPL_TMP'] = 'tmp/'; | ||
61 | // Raintpl template directory (keep the trailing slash!) | ||
62 | $GLOBALS['config']['RAINTPL_TPL'] = 'tpl/'; | ||
63 | |||
64 | // Thumbnail cache directory | ||
65 | $GLOBALS['config']['CACHEDIR'] = 'cache'; | ||
66 | |||
67 | // Atom & RSS feed cache directory | ||
68 | $GLOBALS['config']['PAGECACHE'] = 'pagecache'; | ||
69 | |||
70 | /* | ||
71 | * Global configuration | ||
72 | */ | ||
73 | // Ban IP after this many failures | ||
74 | $GLOBALS['config']['BAN_AFTER'] = 4; | ||
75 | // Ban duration for IP address after login failures (in seconds) | ||
76 | $GLOBALS['config']['BAN_DURATION'] = 1800; | ||
77 | |||
78 | // Feed options | ||
79 | // Enable RSS permalinks by default. | ||
80 | // This corresponds to the default behavior of shaarli before this was added as an option. | ||
81 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = true; | ||
82 | // If true, an extra "ATOM feed" button will be displayed in the toolbar | ||
83 | $GLOBALS['config']['SHOW_ATOM'] = false; | ||
84 | |||
85 | // Link display options | ||
86 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = false; | ||
87 | $GLOBALS['config']['HIDE_TIMESTAMPS'] = false; | ||
88 | $GLOBALS['config']['LINKS_PER_PAGE'] = 20; | ||
89 | |||
90 | // Open Shaarli (true): anyone can add/edit/delete links without having to login | ||
91 | $GLOBALS['config']['OPEN_SHAARLI'] = false; | ||
92 | |||
93 | // Thumbnails | ||
94 | // Display thumbnails in links | ||
95 | $GLOBALS['config']['ENABLE_THUMBNAILS'] = true; | ||
96 | // Store thumbnails in a local cache | ||
97 | $GLOBALS['config']['ENABLE_LOCALCACHE'] = true; | ||
98 | |||
99 | // Update check frequency for Shaarli. 86400 seconds=24 hours | ||
100 | $GLOBALS['config']['UPDATECHECK_BRANCH'] = 'stable'; | ||
101 | $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400; | ||
102 | |||
103 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] = true; | ||
104 | |||
105 | /* | ||
106 | * Plugin configuration | ||
107 | * | ||
108 | * Warning: order matters! | ||
109 | * | ||
110 | * These settings may be be overriden in: | ||
111 | * - data/config.php | ||
112 | * - each plugin's configuration file | ||
113 | */ | ||
114 | //$GLOBALS['config']['ENABLED_PLUGINS'] = array( | ||
115 | // 'qrcode', 'archiveorg', 'readityourself', 'demo_plugin', 'playvideos', | ||
116 | // 'wallabag', 'markdown', 'addlink_toolbar', | ||
117 | //); | ||
118 | $GLOBALS['config']['ENABLED_PLUGINS'] = array('qrcode'); | ||
119 | |||
120 | // Initialize plugin parameters array. | ||
121 | $GLOBALS['plugins'] = array(); | ||
122 | |||
123 | // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable. | ||
124 | $GLOBALS['config']['PUBSUBHUB_URL'] = ''; | ||
125 | |||
126 | /* | 25 | /* |
127 | * PHP configuration | 26 | * PHP configuration |
128 | */ | 27 | */ |
129 | define('shaarli_version', '0.7.0'); | 28 | define('shaarli_version', '0.8.2'); |
130 | 29 | ||
131 | // http://server.com/x/shaarli --> /shaarli/ | 30 | // http://server.com/x/shaarli --> /shaarli/ |
132 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 31 | define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0))); |
133 | 32 | ||
134 | // High execution time in case of problematic imports/exports. | 33 | // High execution time in case of problematic imports/exports. |
135 | ini_set('max_input_time','60'); | 34 | ini_set('max_input_time','60'); |
@@ -144,20 +43,31 @@ error_reporting(E_ALL^E_WARNING); | |||
144 | // See all errors (for debugging only) | 43 | // See all errors (for debugging only) |
145 | //error_reporting(-1); | 44 | //error_reporting(-1); |
146 | 45 | ||
147 | /* | 46 | |
148 | * User configuration | 47 | // 3rd-party libraries |
149 | */ | 48 | if (! file_exists(__DIR__ . '/vendor/autoload.php')) { |
150 | if (is_file($GLOBALS['config']['CONFIG_FILE'])) { | 49 | header('Content-Type: text/plain; charset=utf-8'); |
151 | require_once $GLOBALS['config']['CONFIG_FILE']; | 50 | echo "Error: missing Composer configuration\n\n" |
51 | ."If you installed Shaarli through Git or using the development branch,\n" | ||
52 | ."please refer to the installation documentation to install PHP" | ||
53 | ." dependencies using Composer:\n" | ||
54 | ."- https://github.com/shaarli/Shaarli/wiki/Server-requirements\n" | ||
55 | ."- https://github.com/shaarli/Shaarli/wiki/Download-and-Installation"; | ||
56 | exit; | ||
152 | } | 57 | } |
58 | require_once 'inc/rain.tpl.class.php'; | ||
59 | require_once __DIR__ . '/vendor/autoload.php'; | ||
153 | 60 | ||
154 | // Shaarli library | 61 | // Shaarli library |
155 | require_once 'application/ApplicationUtils.php'; | 62 | require_once 'application/ApplicationUtils.php'; |
156 | require_once 'application/Cache.php'; | 63 | require_once 'application/Cache.php'; |
157 | require_once 'application/CachedPage.php'; | 64 | require_once 'application/CachedPage.php'; |
65 | require_once 'application/config/ConfigManager.php'; | ||
66 | require_once 'application/config/ConfigPlugin.php'; | ||
158 | require_once 'application/FeedBuilder.php'; | 67 | require_once 'application/FeedBuilder.php'; |
159 | require_once 'application/FileUtils.php'; | 68 | require_once 'application/FileUtils.php'; |
160 | require_once 'application/HttpUtils.php'; | 69 | require_once 'application/HttpUtils.php'; |
70 | require_once 'application/Languages.php'; | ||
161 | require_once 'application/LinkDB.php'; | 71 | require_once 'application/LinkDB.php'; |
162 | require_once 'application/LinkFilter.php'; | 72 | require_once 'application/LinkFilter.php'; |
163 | require_once 'application/LinkUtils.php'; | 73 | require_once 'application/LinkUtils.php'; |
@@ -166,7 +76,6 @@ require_once 'application/PageBuilder.php'; | |||
166 | require_once 'application/TimeZone.php'; | 76 | require_once 'application/TimeZone.php'; |
167 | require_once 'application/Url.php'; | 77 | require_once 'application/Url.php'; |
168 | require_once 'application/Utils.php'; | 78 | require_once 'application/Utils.php'; |
169 | require_once 'application/Config.php'; | ||
170 | require_once 'application/PluginManager.php'; | 79 | require_once 'application/PluginManager.php'; |
171 | require_once 'application/Router.php'; | 80 | require_once 'application/Router.php'; |
172 | require_once 'application/Updater.php'; | 81 | require_once 'application/Updater.php'; |
@@ -210,15 +119,18 @@ if (isset($_COOKIE['shaarli']) && !is_session_id_valid($_COOKIE['shaarli'])) { | |||
210 | $_COOKIE['shaarli'] = session_id(); | 119 | $_COOKIE['shaarli'] = session_id(); |
211 | } | 120 | } |
212 | 121 | ||
213 | include "inc/rain.tpl.class.php"; //include Rain TPL | 122 | $conf = new ConfigManager(); |
214 | raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory | 123 | $conf->setEmpty('general.timezone', date_default_timezone_get()); |
215 | raintpl::$cache_dir = $GLOBALS['config']['RAINTPL_TMP']; // cache directory | 124 | $conf->setEmpty('general.title', 'Shared links on '. escape(index_url($_SERVER))); |
125 | RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl'); // template directory | ||
126 | RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory | ||
216 | 127 | ||
217 | $pluginManager = PluginManager::getInstance(); | 128 | $pluginManager = new PluginManager($conf); |
218 | $pluginManager->load($GLOBALS['config']['ENABLED_PLUGINS']); | 129 | $pluginManager->load($conf->get('general.enabled_plugins')); |
219 | 130 | ||
220 | ob_start(); // Output buffering for the page cache. | 131 | date_default_timezone_set($conf->get('general.timezone', 'UTC')); |
221 | 132 | ||
133 | ob_start(); // Output buffering for the page cache. | ||
222 | 134 | ||
223 | // In case stupid admin has left magic_quotes enabled in php.ini: | 135 | // In case stupid admin has left magic_quotes enabled in php.ini: |
224 | if (get_magic_quotes_gpc()) | 136 | if (get_magic_quotes_gpc()) |
@@ -235,18 +147,9 @@ header("Cache-Control: no-store, no-cache, must-revalidate"); | |||
235 | header("Cache-Control: post-check=0, pre-check=0", false); | 147 | header("Cache-Control: post-check=0, pre-check=0", false); |
236 | header("Pragma: no-cache"); | 148 | header("Pragma: no-cache"); |
237 | 149 | ||
238 | // Handling of old config file which do not have the new parameters. | 150 | if (! is_file($conf->getConfigFileExt())) { |
239 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(index_url($_SERVER)); | ||
240 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); | ||
241 | if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; | ||
242 | if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; | ||
243 | if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false; | ||
244 | if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?'; | ||
245 | // I really need to rewrite Shaarli with a proper configuation manager. | ||
246 | |||
247 | if (! is_file($GLOBALS['config']['CONFIG_FILE'])) { | ||
248 | // Ensure Shaarli has proper access to its resources | 151 | // Ensure Shaarli has proper access to its resources |
249 | $errors = ApplicationUtils::checkResourcePermissions($GLOBALS['config']); | 152 | $errors = ApplicationUtils::checkResourcePermissions($conf); |
250 | 153 | ||
251 | if ($errors != array()) { | 154 | if ($errors != array()) { |
252 | $message = '<p>Insufficient permissions:</p><ul>'; | 155 | $message = '<p>Insufficient permissions:</p><ul>'; |
@@ -262,15 +165,11 @@ if (! is_file($GLOBALS['config']['CONFIG_FILE'])) { | |||
262 | } | 165 | } |
263 | 166 | ||
264 | // Display the installation form if no existing config is found | 167 | // Display the installation form if no existing config is found |
265 | install(); | 168 | install($conf); |
266 | } | 169 | } |
267 | 170 | ||
268 | $GLOBALS['title'] = !empty($GLOBALS['title']) ? escape($GLOBALS['title']) : ''; | ||
269 | $GLOBALS['titleLink'] = !empty($GLOBALS['titleLink']) ? escape($GLOBALS['titleLink']) : ''; | ||
270 | $GLOBALS['redirector'] = !empty($GLOBALS['redirector']) ? escape($GLOBALS['redirector']) : ''; | ||
271 | |||
272 | // a token depending of deployment salt, user password, and the current ip | 171 | // a token depending of deployment salt, user password, and the current ip |
273 | define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt'])); | 172 | define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); |
274 | 173 | ||
275 | // Sniff browser language and set date format accordingly. | 174 | // Sniff browser language and set date format accordingly. |
276 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | 175 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { |
@@ -278,17 +177,21 @@ if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | |||
278 | } | 177 | } |
279 | header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. | 178 | header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. |
280 | 179 | ||
281 | //================================================================================================== | 180 | /** |
282 | // Checking session state (i.e. is the user still logged in) | 181 | * Checking session state (i.e. is the user still logged in) |
283 | //================================================================================================== | 182 | * |
284 | 183 | * @param ConfigManager $conf The configuration manager. | |
285 | function setup_login_state() { | 184 | * |
286 | if ($GLOBALS['config']['OPEN_SHAARLI']) { | 185 | * @return bool: true if the user is logged in, false otherwise. |
186 | */ | ||
187 | function setup_login_state($conf) | ||
188 | { | ||
189 | if ($conf->get('security.open_shaarli')) { | ||
287 | return true; | 190 | return true; |
288 | } | 191 | } |
289 | $userIsLoggedIn = false; // By default, we do not consider the user as logged in; | 192 | $userIsLoggedIn = false; // By default, we do not consider the user as logged in; |
290 | $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met. | 193 | $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met. |
291 | if (!isset($GLOBALS['login'])) { | 194 | if (! $conf->exists('credentials.login')) { |
292 | $userIsLoggedIn = false; // Shaarli is not configured yet. | 195 | $userIsLoggedIn = false; // Shaarli is not configured yet. |
293 | $loginFailure = true; | 196 | $loginFailure = true; |
294 | } | 197 | } |
@@ -296,13 +199,13 @@ function setup_login_state() { | |||
296 | $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && | 199 | $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && |
297 | !$loginFailure) | 200 | !$loginFailure) |
298 | { | 201 | { |
299 | fillSessionInfo(); | 202 | fillSessionInfo($conf); |
300 | $userIsLoggedIn = true; | 203 | $userIsLoggedIn = true; |
301 | } | 204 | } |
302 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. | 205 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. |
303 | if (empty($_SESSION['uid']) || | 206 | if (empty($_SESSION['uid']) |
304 | ($GLOBALS['disablesessionprotection']==false && $_SESSION['ip']!=allIPs()) || | 207 | || ($conf->get('security.session_protection_disabled') == false && $_SESSION['ip'] != allIPs()) |
305 | time() >= $_SESSION['expires_on']) | 208 | || time() >= $_SESSION['expires_on']) |
306 | { | 209 | { |
307 | logout(); | 210 | logout(); |
308 | $userIsLoggedIn = false; | 211 | $userIsLoggedIn = false; |
@@ -320,22 +223,26 @@ function setup_login_state() { | |||
320 | 223 | ||
321 | return $userIsLoggedIn; | 224 | return $userIsLoggedIn; |
322 | } | 225 | } |
323 | $userIsLoggedIn = setup_login_state(); | 226 | $userIsLoggedIn = setup_login_state($conf); |
324 | 227 | ||
325 | // ------------------------------------------------------------------------------------------ | 228 | /** |
326 | // PubSubHubbub protocol support (if enabled) [UNTESTED] | 229 | * PubSubHubbub protocol support (if enabled) [UNTESTED] |
327 | // (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ ) | 230 | * (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ ) |
328 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) include './publisher.php'; | 231 | * |
329 | function pubsubhub() | 232 | * @param ConfigManager $conf Configuration Manager instance. |
233 | */ | ||
234 | function pubsubhub($conf) | ||
330 | { | 235 | { |
331 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) | 236 | $pshUrl = $conf->get('config.PUBSUBHUB_URL'); |
237 | if (!empty($pshUrl)) | ||
332 | { | 238 | { |
333 | $p = new Publisher($GLOBALS['config']['PUBSUBHUB_URL']); | 239 | include_once './publisher.php'; |
334 | $topic_url = array ( | 240 | $p = new Publisher($pshUrl); |
335 | index_url($_SERVER).'?do=atom', | 241 | $topic_url = array ( |
336 | index_url($_SERVER).'?do=rss' | 242 | index_url($_SERVER).'?do=atom', |
337 | ); | 243 | index_url($_SERVER).'?do=rss' |
338 | $p->publish_update($topic_url); | 244 | ); |
245 | $p->publish_update($topic_url); | ||
339 | } | 246 | } |
340 | } | 247 | } |
341 | 248 | ||
@@ -345,32 +252,46 @@ function pubsubhub() | |||
345 | // Returns the IP address of the client (Used to prevent session cookie hijacking.) | 252 | // Returns the IP address of the client (Used to prevent session cookie hijacking.) |
346 | function allIPs() | 253 | function allIPs() |
347 | { | 254 | { |
348 | $ip = $_SERVER["REMOTE_ADDR"]; | 255 | $ip = $_SERVER['REMOTE_ADDR']; |
349 | // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy. | 256 | // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy. |
350 | if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; } | 257 | if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; } |
351 | if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; } | 258 | if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; } |
352 | return $ip; | 259 | return $ip; |
353 | } | 260 | } |
354 | 261 | ||
355 | function fillSessionInfo() { | 262 | /** |
263 | * Load user session. | ||
264 | * | ||
265 | * @param ConfigManager $conf Configuration Manager instance. | ||
266 | */ | ||
267 | function fillSessionInfo($conf) | ||
268 | { | ||
356 | $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) | 269 | $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) |
357 | $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. | 270 | $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. |
358 | $_SESSION['username']=$GLOBALS['login']; | 271 | $_SESSION['username']= $conf->get('credentials.login'); |
359 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. | 272 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. |
360 | } | 273 | } |
361 | 274 | ||
362 | // Check that user/password is correct. | 275 | /** |
363 | function check_auth($login,$password) | 276 | * Check that user/password is correct. |
277 | * | ||
278 | * @param string $login Username | ||
279 | * @param string $password User password | ||
280 | * @param ConfigManager $conf Configuration Manager instance. | ||
281 | * | ||
282 | * @return bool: authentication successful or not. | ||
283 | */ | ||
284 | function check_auth($login, $password, $conf) | ||
364 | { | 285 | { |
365 | $hash = sha1($password.$login.$GLOBALS['salt']); | 286 | $hash = sha1($password . $login . $conf->get('credentials.salt')); |
366 | if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash']) | 287 | if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) |
367 | { // Login/password is correct. | 288 | { // Login/password is correct. |
368 | fillSessionInfo(); | 289 | fillSessionInfo($conf); |
369 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Login successful'); | 290 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful'); |
370 | return True; | 291 | return true; |
371 | } | 292 | } |
372 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Login failed for user '.$login); | 293 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login failed for user '.$login); |
373 | return False; | 294 | return false; |
374 | } | 295 | } |
375 | 296 | ||
376 | // Returns true if the user is logged in. | 297 | // Returns true if the user is logged in. |
@@ -395,34 +316,71 @@ function logout() { | |||
395 | // ------------------------------------------------------------------------------------------ | 316 | // ------------------------------------------------------------------------------------------ |
396 | // Brute force protection system | 317 | // Brute force protection system |
397 | // Several consecutive failed logins will ban the IP address for 30 minutes. | 318 | // Several consecutive failed logins will ban the IP address for 30 minutes. |
398 | 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?>"); | 319 | if (!is_file($conf->get('resource.ban_file', 'data/ipbans.php'))) { |
399 | include $GLOBALS['config']['IPBANS_FILENAME']; | 320 | // FIXME! globals |
400 | // Signal a failed login. Will ban the IP if too many failures: | 321 | file_put_contents( |
401 | function ban_loginFailed() | 322 | $conf->get('resource.ban_file', 'data/ipbans.php'), |
323 | "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>" | ||
324 | ); | ||
325 | } | ||
326 | include $conf->get('resource.ban_file', 'data/ipbans.php'); | ||
327 | /** | ||
328 | * Signal a failed login. Will ban the IP if too many failures: | ||
329 | * | ||
330 | * @param ConfigManager $conf Configuration Manager instance. | ||
331 | */ | ||
332 | function ban_loginFailed($conf) | ||
402 | { | 333 | { |
403 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 334 | $ip = $_SERVER['REMOTE_ADDR']; |
404 | if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0; | 335 | $trusted = $conf->get('security.trusted_proxies', array()); |
336 | if (in_array($ip, $trusted)) { | ||
337 | $ip = getIpAddressFromProxy($_SERVER, $trusted); | ||
338 | if (!$ip) { | ||
339 | return; | ||
340 | } | ||
341 | } | ||
342 | $gb = $GLOBALS['IPBANS']; | ||
343 | if (! isset($gb['FAILURES'][$ip])) { | ||
344 | $gb['FAILURES'][$ip]=0; | ||
345 | } | ||
405 | $gb['FAILURES'][$ip]++; | 346 | $gb['FAILURES'][$ip]++; |
406 | if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1)) | 347 | if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1)) |
407 | { | 348 | { |
408 | $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION']; | 349 | $gb['BANS'][$ip] = time() + $conf->get('security.ban_after', 1800); |
409 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'IP address banned from login'); | 350 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'IP address banned from login'); |
410 | } | 351 | } |
411 | $GLOBALS['IPBANS'] = $gb; | 352 | $GLOBALS['IPBANS'] = $gb; |
412 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 353 | file_put_contents( |
354 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
355 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
356 | ); | ||
413 | } | 357 | } |
414 | 358 | ||
415 | // Signals a successful login. Resets failed login counter. | 359 | /** |
416 | function ban_loginOk() | 360 | * Signals a successful login. Resets failed login counter. |
361 | * | ||
362 | * @param ConfigManager $conf Configuration Manager instance. | ||
363 | */ | ||
364 | function ban_loginOk($conf) | ||
417 | { | 365 | { |
418 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 366 | $ip = $_SERVER['REMOTE_ADDR']; |
367 | $gb = $GLOBALS['IPBANS']; | ||
419 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | 368 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); |
420 | $GLOBALS['IPBANS'] = $gb; | 369 | $GLOBALS['IPBANS'] = $gb; |
421 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 370 | file_put_contents( |
371 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
372 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
373 | ); | ||
422 | } | 374 | } |
423 | 375 | ||
424 | // Checks if the user CAN login. If 'true', the user can try to login. | 376 | /** |
425 | function ban_canLogin() | 377 | * Checks if the user CAN login. If 'true', the user can try to login. |
378 | * | ||
379 | * @param ConfigManager $conf Configuration Manager instance. | ||
380 | * | ||
381 | * @return bool: true if the user is allowed to login. | ||
382 | */ | ||
383 | function ban_canLogin($conf) | ||
426 | { | 384 | { |
427 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 385 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; |
428 | if (isset($gb['BANS'][$ip])) | 386 | if (isset($gb['BANS'][$ip])) |
@@ -430,9 +388,12 @@ function ban_canLogin() | |||
430 | // User is banned. Check if the ban has expired: | 388 | // User is banned. Check if the ban has expired: |
431 | if ($gb['BANS'][$ip]<=time()) | 389 | if ($gb['BANS'][$ip]<=time()) |
432 | { // Ban expired, user can try to login again. | 390 | { // Ban expired, user can try to login again. |
433 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Ban lifted.'); | 391 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Ban lifted.'); |
434 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | 392 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); |
435 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 393 | file_put_contents( |
394 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
395 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
396 | ); | ||
436 | return true; // Ban has expired, user can login. | 397 | return true; // Ban has expired, user can login. |
437 | } | 398 | } |
438 | return false; // User is banned. | 399 | return false; // User is banned. |
@@ -444,10 +405,12 @@ function ban_canLogin() | |||
444 | // Process login form: Check if login/password is correct. | 405 | // Process login form: Check if login/password is correct. |
445 | if (isset($_POST['login'])) | 406 | if (isset($_POST['login'])) |
446 | { | 407 | { |
447 | if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.'); | 408 | if (!ban_canLogin($conf)) die('I said: NO. You are banned for the moment. Go away.'); |
448 | if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password']))) | 409 | if (isset($_POST['password']) |
449 | { // Login/password is OK. | 410 | && tokenOk($_POST['token']) |
450 | ban_loginOk(); | 411 | && (check_auth($_POST['login'], $_POST['password'], $conf)) |
412 | ) { // Login/password is OK. | ||
413 | ban_loginOk($conf); | ||
451 | // If user wants to keep the session cookie even after the browser closes: | 414 | // If user wants to keep the session cookie even after the browser closes: |
452 | if (!empty($_POST['longlastingsession'])) | 415 | if (!empty($_POST['longlastingsession'])) |
453 | { | 416 | { |
@@ -495,7 +458,7 @@ if (isset($_POST['login'])) | |||
495 | } | 458 | } |
496 | else | 459 | else |
497 | { | 460 | { |
498 | ban_loginFailed(); | 461 | ban_loginFailed($conf); |
499 | $redir = '&username='. $_POST['login']; | 462 | $redir = '&username='. $_POST['login']; |
500 | if (isset($_GET['post'])) { | 463 | if (isset($_GET['post'])) { |
501 | $redir .= '&post=' . urlencode($_GET['post']); | 464 | $redir .= '&post=' . urlencode($_GET['post']); |
@@ -543,10 +506,16 @@ function getMaxFileSize() | |||
543 | // Token should be used in any form which acts on data (create,update,delete,import...). | 506 | // Token should be used in any form which acts on data (create,update,delete,import...). |
544 | if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. | 507 | if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. |
545 | 508 | ||
546 | // Returns a token. | 509 | /** |
547 | function getToken() | 510 | * Returns a token. |
511 | * | ||
512 | * @param ConfigManager $conf Configuration Manager instance. | ||
513 | * | ||
514 | * @return string token. | ||
515 | */ | ||
516 | function getToken($conf) | ||
548 | { | 517 | { |
549 | $rnd = sha1(uniqid('',true).'_'.mt_rand().$GLOBALS['salt']); // We generate a random string. | 518 | $rnd = sha1(uniqid('', true) .'_'. mt_rand() . $conf->get('credentials.salt')); // We generate a random string. |
550 | $_SESSION['tokens'][$rnd]=1; // Store it on the server side. | 519 | $_SESSION['tokens'][$rnd]=1; // Store it on the server side. |
551 | return $rnd; | 520 | return $rnd; |
552 | } | 521 | } |
@@ -563,15 +532,18 @@ function tokenOk($token) | |||
563 | return false; // Wrong token, or already used. | 532 | return false; // Wrong token, or already used. |
564 | } | 533 | } |
565 | 534 | ||
566 | // ------------------------------------------------------------------------------------------ | 535 | /** |
567 | // Daily RSS feed: 1 RSS entry per day giving all the links on that day. | 536 | * Daily RSS feed: 1 RSS entry per day giving all the links on that day. |
568 | // Gives the last 7 days (which have links). | 537 | * Gives the last 7 days (which have links). |
569 | // This RSS feed cannot be filtered. | 538 | * This RSS feed cannot be filtered. |
570 | function showDailyRSS() { | 539 | * |
540 | * @param ConfigManager $conf Configuration Manager instance. | ||
541 | */ | ||
542 | function showDailyRSS($conf) { | ||
571 | // Cache system | 543 | // Cache system |
572 | $query = $_SERVER['QUERY_STRING']; | 544 | $query = $_SERVER['QUERY_STRING']; |
573 | $cache = new CachedPage( | 545 | $cache = new CachedPage( |
574 | $GLOBALS['config']['PAGECACHE'], | 546 | $conf->get('config.PAGE_CACHE'), |
575 | page_url($_SERVER), | 547 | page_url($_SERVER), |
576 | startsWith($query,'do=dailyrss') && !isLoggedIn() | 548 | startsWith($query,'do=dailyrss') && !isLoggedIn() |
577 | ); | 549 | ); |
@@ -584,32 +556,27 @@ function showDailyRSS() { | |||
584 | // If cached was not found (or not usable), then read the database and build the response: | 556 | // If cached was not found (or not usable), then read the database and build the response: |
585 | // Read links from database (and filter private links if used it not logged in). | 557 | // Read links from database (and filter private links if used it not logged in). |
586 | $LINKSDB = new LinkDB( | 558 | $LINKSDB = new LinkDB( |
587 | $GLOBALS['config']['DATASTORE'], | 559 | $conf->get('resource.datastore'), |
588 | isLoggedIn(), | 560 | isLoggedIn(), |
589 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | 561 | $conf->get('privacy.hide_public_links'), |
590 | $GLOBALS['redirector'], | 562 | $conf->get('redirector.url'), |
591 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] | 563 | $conf->get('redirector.encode_url') |
592 | ); | 564 | ); |
593 | 565 | ||
594 | /* Some Shaarlies may have very few links, so we need to look | 566 | /* Some Shaarlies may have very few links, so we need to look |
595 | back in time (rsort()) until we have enough days ($nb_of_days). | 567 | back in time until we have enough days ($nb_of_days). |
596 | */ | 568 | */ |
597 | $linkdates = array(); | ||
598 | foreach ($LINKSDB as $linkdate => $value) { | ||
599 | $linkdates[] = $linkdate; | ||
600 | } | ||
601 | rsort($linkdates); | ||
602 | $nb_of_days = 7; // We take 7 days. | 569 | $nb_of_days = 7; // We take 7 days. |
603 | $today = Date('Ymd'); | 570 | $today = date('Ymd'); |
604 | $days = array(); | 571 | $days = array(); |
605 | 572 | ||
606 | foreach ($linkdates as $linkdate) { | 573 | foreach ($LINKSDB as $link) { |
607 | $day = substr($linkdate, 0, 8); // Extract day (without time) | 574 | $day = $link['created']->format('Ymd'); // Extract day (without time) |
608 | if (strcmp($day,$today) < 0) { | 575 | if (strcmp($day, $today) < 0) { |
609 | if (empty($days[$day])) { | 576 | if (empty($days[$day])) { |
610 | $days[$day] = array(); | 577 | $days[$day] = array(); |
611 | } | 578 | } |
612 | $days[$day][] = $linkdate; | 579 | $days[$day][] = $link; |
613 | } | 580 | } |
614 | 581 | ||
615 | if (count($days) > $nb_of_days) { | 582 | if (count($days) > $nb_of_days) { |
@@ -622,42 +589,35 @@ function showDailyRSS() { | |||
622 | $pageaddr = escape(index_url($_SERVER)); | 589 | $pageaddr = escape(index_url($_SERVER)); |
623 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">'; | 590 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">'; |
624 | echo '<channel>'; | 591 | echo '<channel>'; |
625 | echo '<title>Daily - '. $GLOBALS['title'] . '</title>'; | 592 | echo '<title>Daily - '. $conf->get('general.title') . '</title>'; |
626 | echo '<link>'. $pageaddr .'</link>'; | 593 | echo '<link>'. $pageaddr .'</link>'; |
627 | echo '<description>Daily shared links</description>'; | 594 | echo '<description>Daily shared links</description>'; |
628 | echo '<language>en-en</language>'; | 595 | echo '<language>en-en</language>'; |
629 | echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL; | 596 | echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL; |
630 | 597 | ||
631 | // For each day. | 598 | // For each day. |
632 | foreach ($days as $day => $linkdates) { | 599 | foreach ($days as $day => $links) { |
633 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); | 600 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); |
634 | $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. | 601 | $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. |
635 | 602 | ||
636 | // Build the HTML body of this RSS entry. | ||
637 | $html = ''; | ||
638 | $href = ''; | ||
639 | $links = array(); | ||
640 | |||
641 | // We pre-format some fields for proper output. | 603 | // We pre-format some fields for proper output. |
642 | foreach ($linkdates as $linkdate) { | 604 | foreach ($links as &$link) { |
643 | $l = $LINKSDB[$linkdate]; | 605 | $link['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); |
644 | $l['formatedDescription'] = format_description($l['description'], $GLOBALS['redirector']); | 606 | $link['thumbnail'] = thumbnail($conf, $link['url']); |
645 | $l['thumbnail'] = thumbnail($l['url']); | 607 | $link['timestamp'] = $link['created']->getTimestamp(); |
646 | $l_date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $l['linkdate']); | 608 | if (startsWith($link['url'], '?')) { |
647 | $l['timestamp'] = $l_date->getTimestamp(); | 609 | $link['url'] = index_url($_SERVER) . $link['url']; // make permalink URL absolute |
648 | if (startsWith($l['url'], '?')) { | ||
649 | $l['url'] = index_url($_SERVER) . $l['url']; // make permalink URL absolute | ||
650 | } | 610 | } |
651 | $links[$linkdate] = $l; | ||
652 | } | 611 | } |
653 | 612 | ||
654 | // Then build the HTML for this day: | 613 | // Then build the HTML for this day: |
655 | $tpl = new RainTPL; | 614 | $tpl = new RainTPL; |
656 | $tpl->assign('title', $GLOBALS['title']); | 615 | $tpl->assign('title', $conf->get('general.title')); |
657 | $tpl->assign('daydate', $dayDate->getTimestamp()); | 616 | $tpl->assign('daydate', $dayDate->getTimestamp()); |
658 | $tpl->assign('absurl', $absurl); | 617 | $tpl->assign('absurl', $absurl); |
659 | $tpl->assign('links', $links); | 618 | $tpl->assign('links', $links); |
660 | $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS))); | 619 | $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS))); |
620 | $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false)); | ||
661 | $html = $tpl->draw('dailyrss', $return_string=true); | 621 | $html = $tpl->draw('dailyrss', $return_string=true); |
662 | 622 | ||
663 | echo $html . PHP_EOL; | 623 | echo $html . PHP_EOL; |
@@ -672,12 +632,14 @@ function showDailyRSS() { | |||
672 | /** | 632 | /** |
673 | * Show the 'Daily' page. | 633 | * Show the 'Daily' page. |
674 | * | 634 | * |
675 | * @param PageBuilder $pageBuilder Template engine wrapper. | 635 | * @param PageBuilder $pageBuilder Template engine wrapper. |
676 | * @param LinkDB $LINKSDB LinkDB instance. | 636 | * @param LinkDB $LINKSDB LinkDB instance. |
637 | * @param ConfigManager $conf Configuration Manager instance. | ||
638 | * @param PluginManager $pluginManager Plugin Manager instane. | ||
677 | */ | 639 | */ |
678 | function showDaily($pageBuilder, $LINKSDB) | 640 | function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) |
679 | { | 641 | { |
680 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. | 642 | $day=date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. |
681 | if (isset($_GET['day'])) $day=$_GET['day']; | 643 | if (isset($_GET['day'])) $day=$_GET['day']; |
682 | 644 | ||
683 | $days = $LINKSDB->days(); | 645 | $days = $LINKSDB->days(); |
@@ -705,10 +667,9 @@ function showDaily($pageBuilder, $LINKSDB) | |||
705 | $taglist = explode(' ',$link['tags']); | 667 | $taglist = explode(' ',$link['tags']); |
706 | uasort($taglist, 'strcasecmp'); | 668 | uasort($taglist, 'strcasecmp'); |
707 | $linksToDisplay[$key]['taglist']=$taglist; | 669 | $linksToDisplay[$key]['taglist']=$taglist; |
708 | $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $GLOBALS['redirector']); | 670 | $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); |
709 | $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); | 671 | $linksToDisplay[$key]['thumbnail'] = thumbnail($conf, $link['url']); |
710 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 672 | $linksToDisplay[$key]['timestamp'] = $link['created']->getTimestamp(); |
711 | $linksToDisplay[$key]['timestamp'] = $date->getTimestamp(); | ||
712 | } | 673 | } |
713 | 674 | ||
714 | /* We need to spread the articles on 3 columns. | 675 | /* We need to spread the articles on 3 columns. |
@@ -741,7 +702,7 @@ function showDaily($pageBuilder, $LINKSDB) | |||
741 | 'previousday' => $previousday, | 702 | 'previousday' => $previousday, |
742 | 'nextday' => $nextday, | 703 | 'nextday' => $nextday, |
743 | ); | 704 | ); |
744 | $pluginManager = PluginManager::getInstance(); | 705 | |
745 | $pluginManager->executeHooks('render_daily', $data, array('loggedin' => isLoggedIn())); | 706 | $pluginManager->executeHooks('render_daily', $data, array('loggedin' => isLoggedIn())); |
746 | 707 | ||
747 | foreach ($data as $key => $value) { | 708 | foreach ($data as $key => $value) { |
@@ -752,36 +713,46 @@ function showDaily($pageBuilder, $LINKSDB) | |||
752 | exit; | 713 | exit; |
753 | } | 714 | } |
754 | 715 | ||
755 | // Renders the linklist | 716 | /** |
756 | function showLinkList($PAGE, $LINKSDB) { | 717 | * Renders the linklist |
757 | buildLinkList($PAGE,$LINKSDB); // Compute list of links to display | 718 | * |
719 | * @param pageBuilder $PAGE pageBuilder instance. | ||
720 | * @param LinkDB $LINKSDB LinkDB instance. | ||
721 | * @param ConfigManager $conf Configuration Manager instance. | ||
722 | * @param PluginManager $pluginManager Plugin Manager instance. | ||
723 | */ | ||
724 | function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { | ||
725 | buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager); // Compute list of links to display | ||
758 | $PAGE->renderPage('linklist'); | 726 | $PAGE->renderPage('linklist'); |
759 | } | 727 | } |
760 | 728 | ||
761 | 729 | /** | |
762 | // ------------------------------------------------------------------------------------------ | 730 | * Render HTML page (according to URL parameters and user rights) |
763 | // Render HTML page (according to URL parameters and user rights) | 731 | * |
764 | function renderPage() | 732 | * @param ConfigManager $conf Configuration Manager instance. |
733 | * @param PluginManager $pluginManager Plugin Manager instance, | ||
734 | */ | ||
735 | function renderPage($conf, $pluginManager) | ||
765 | { | 736 | { |
766 | $LINKSDB = new LinkDB( | 737 | $LINKSDB = new LinkDB( |
767 | $GLOBALS['config']['DATASTORE'], | 738 | $conf->get('resource.datastore'), |
768 | isLoggedIn(), | 739 | isLoggedIn(), |
769 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | 740 | $conf->get('privacy.hide_public_links'), |
770 | $GLOBALS['redirector'], | 741 | $conf->get('redirector.url'), |
771 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] | 742 | $conf->get('redirector.encode_url') |
772 | ); | 743 | ); |
773 | 744 | ||
774 | $updater = new Updater( | 745 | $updater = new Updater( |
775 | read_updates_file($GLOBALS['config']['UPDATES_FILE']), | 746 | read_updates_file($conf->get('resource.updates')), |
776 | $GLOBALS, | ||
777 | $LINKSDB, | 747 | $LINKSDB, |
748 | $conf, | ||
778 | isLoggedIn() | 749 | isLoggedIn() |
779 | ); | 750 | ); |
780 | try { | 751 | try { |
781 | $newUpdates = $updater->update(); | 752 | $newUpdates = $updater->update(); |
782 | if (! empty($newUpdates)) { | 753 | if (! empty($newUpdates)) { |
783 | write_updates_file( | 754 | write_updates_file( |
784 | $GLOBALS['config']['UPDATES_FILE'], | 755 | $conf->get('resource.updates'), |
785 | $updater->getDoneUpdates() | 756 | $updater->getDoneUpdates() |
786 | ); | 757 | ); |
787 | } | 758 | } |
@@ -790,9 +761,10 @@ function renderPage() | |||
790 | die($e->getMessage()); | 761 | die($e->getMessage()); |
791 | } | 762 | } |
792 | 763 | ||
793 | $PAGE = new PageBuilder(); | 764 | $PAGE = new PageBuilder($conf); |
794 | $PAGE->assign('linkcount', count($LINKSDB)); | 765 | $PAGE->assign('linkcount', count($LINKSDB)); |
795 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); | 766 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); |
767 | $PAGE->assign('plugin_errors', $pluginManager->getErrors()); | ||
796 | 768 | ||
797 | // Determine which page will be rendered. | 769 | // Determine which page will be rendered. |
798 | $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; | 770 | $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; |
@@ -805,7 +777,7 @@ function renderPage() | |||
805 | 'header', | 777 | 'header', |
806 | 'footer', | 778 | 'footer', |
807 | ); | 779 | ); |
808 | $pluginManager = PluginManager::getInstance(); | 780 | |
809 | foreach($common_hooks as $name) { | 781 | foreach($common_hooks as $name) { |
810 | $plugin_data = array(); | 782 | $plugin_data = array(); |
811 | $pluginManager->executeHooks('render_' . $name, $plugin_data, | 783 | $pluginManager->executeHooks('render_' . $name, $plugin_data, |
@@ -820,9 +792,7 @@ function renderPage() | |||
820 | // -------- Display login form. | 792 | // -------- Display login form. |
821 | if ($targetPage == Router::$PAGE_LOGIN) | 793 | if ($targetPage == Router::$PAGE_LOGIN) |
822 | { | 794 | { |
823 | if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli | 795 | if ($conf->get('security.open_shaarli')) { header('Location: ?'); exit; } // No need to login for open Shaarli |
824 | $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. | ||
825 | $PAGE->assign('token',$token); | ||
826 | if (isset($_GET['username'])) { | 796 | if (isset($_GET['username'])) { |
827 | $PAGE->assign('username', escape($_GET['username'])); | 797 | $PAGE->assign('username', escape($_GET['username'])); |
828 | } | 798 | } |
@@ -833,7 +803,7 @@ function renderPage() | |||
833 | // -------- User wants to logout. | 803 | // -------- User wants to logout. |
834 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) | 804 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) |
835 | { | 805 | { |
836 | invalidateCaches($GLOBALS['config']['PAGECACHE']); | 806 | invalidateCaches($conf->get('resource.page_cache')); |
837 | logout(); | 807 | logout(); |
838 | header('Location: ?'); | 808 | header('Location: ?'); |
839 | exit; | 809 | exit; |
@@ -849,8 +819,8 @@ function renderPage() | |||
849 | // Get only links which have a thumbnail. | 819 | // Get only links which have a thumbnail. |
850 | foreach($links as $link) | 820 | foreach($links as $link) |
851 | { | 821 | { |
852 | $permalink='?'.escape(smallhash($link['linkdate'])); | 822 | $permalink='?'.$link['shorturl']; |
853 | $thumb=lazyThumbnail($link['url'],$permalink); | 823 | $thumb=lazyThumbnail($conf, $link['url'],$permalink); |
854 | if ($thumb!='') // Only output links which have a thumbnail. | 824 | if ($thumb!='') // Only output links which have a thumbnail. |
855 | { | 825 | { |
856 | $link['thumbnail']=$thumb; // Thumbnail HTML code. | 826 | $link['thumbnail']=$thumb; // Thumbnail HTML code. |
@@ -883,7 +853,7 @@ function renderPage() | |||
883 | $maxcount = max($maxcount, $value); | 853 | $maxcount = max($maxcount, $value); |
884 | } | 854 | } |
885 | 855 | ||
886 | // Sort tags alphabetically: case insensitive, support locale if avalaible. | 856 | // Sort tags alphabetically: case insensitive, support locale if available. |
887 | uksort($tags, function($a, $b) { | 857 | uksort($tags, function($a, $b) { |
888 | // Collator is part of PHP intl. | 858 | // Collator is part of PHP intl. |
889 | if (class_exists('Collator')) { | 859 | if (class_exists('Collator')) { |
@@ -922,7 +892,7 @@ function renderPage() | |||
922 | 892 | ||
923 | // Daily page. | 893 | // Daily page. |
924 | if ($targetPage == Router::$PAGE_DAILY) { | 894 | if ($targetPage == Router::$PAGE_DAILY) { |
925 | showDaily($PAGE, $LINKSDB); | 895 | showDaily($PAGE, $LINKSDB, $conf, $pluginManager); |
926 | } | 896 | } |
927 | 897 | ||
928 | // ATOM and RSS feed. | 898 | // ATOM and RSS feed. |
@@ -933,7 +903,7 @@ function renderPage() | |||
933 | // Cache system | 903 | // Cache system |
934 | $query = $_SERVER['QUERY_STRING']; | 904 | $query = $_SERVER['QUERY_STRING']; |
935 | $cache = new CachedPage( | 905 | $cache = new CachedPage( |
936 | $GLOBALS['config']['PAGECACHE'], | 906 | $conf->get('resource.page_cache'), |
937 | page_url($_SERVER), | 907 | page_url($_SERVER), |
938 | startsWith($query,'do='. $targetPage) && !isLoggedIn() | 908 | startsWith($query,'do='. $targetPage) && !isLoggedIn() |
939 | ); | 909 | ); |
@@ -946,15 +916,15 @@ function renderPage() | |||
946 | // Generate data. | 916 | // Generate data. |
947 | $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); | 917 | $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); |
948 | $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); | 918 | $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); |
949 | $feedGenerator->setHideDates($GLOBALS['config']['HIDE_TIMESTAMPS'] && !isLoggedIn()); | 919 | $feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !isLoggedIn()); |
950 | $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS']); | 920 | $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$conf->get('feed.rss_permalinks')); |
951 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) { | 921 | $pshUrl = $conf->get('config.PUBSUBHUB_URL'); |
952 | $feedGenerator->setPubsubhubUrl($GLOBALS['config']['PUBSUBHUB_URL']); | 922 | if (!empty($pshUrl)) { |
923 | $feedGenerator->setPubsubhubUrl($pshUrl); | ||
953 | } | 924 | } |
954 | $data = $feedGenerator->buildData(); | 925 | $data = $feedGenerator->buildData(); |
955 | 926 | ||
956 | // Process plugin hook. | 927 | // Process plugin hook. |
957 | $pluginManager = PluginManager::getInstance(); | ||
958 | $pluginManager->executeHooks('render_feed', $data, array( | 928 | $pluginManager->executeHooks('render_feed', $data, array( |
959 | 'loggedin' => isLoggedIn(), | 929 | 'loggedin' => isLoggedIn(), |
960 | 'target' => $targetPage, | 930 | 'target' => $targetPage, |
@@ -1080,7 +1050,7 @@ function renderPage() | |||
1080 | exit; | 1050 | exit; |
1081 | } | 1051 | } |
1082 | 1052 | ||
1083 | showLinkList($PAGE, $LINKSDB); | 1053 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); |
1084 | if (isset($_GET['edit_link'])) { | 1054 | if (isset($_GET['edit_link'])) { |
1085 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); | 1055 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); |
1086 | exit; | 1056 | exit; |
@@ -1096,6 +1066,7 @@ function renderPage() | |||
1096 | { | 1066 | { |
1097 | $data = array( | 1067 | $data = array( |
1098 | 'pageabsaddr' => index_url($_SERVER), | 1068 | 'pageabsaddr' => index_url($_SERVER), |
1069 | 'sslenabled' => !empty($_SERVER['HTTPS']) | ||
1099 | ); | 1070 | ); |
1100 | $pluginManager->executeHooks('render_tools', $data); | 1071 | $pluginManager->executeHooks('render_tools', $data); |
1101 | 1072 | ||
@@ -1110,19 +1081,23 @@ function renderPage() | |||
1110 | // -------- User wants to change his/her password. | 1081 | // -------- User wants to change his/her password. |
1111 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) | 1082 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) |
1112 | { | 1083 | { |
1113 | if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.'); | 1084 | if ($conf->get('security.open_shaarli')) { |
1085 | die('You are not supposed to change a password on an Open Shaarli.'); | ||
1086 | } | ||
1087 | |||
1114 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) | 1088 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) |
1115 | { | 1089 | { |
1116 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! | 1090 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! |
1117 | 1091 | ||
1118 | // Make sure old password is correct. | 1092 | // Make sure old password is correct. |
1119 | $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1093 | $oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')); |
1120 | if ($oldhash!=$GLOBALS['hash']) { echo '<script>alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; } | 1094 | if ($oldhash!= $conf->get('credentials.hash')) { echo '<script>alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; } |
1121 | // Save new password | 1095 | // Save new password |
1122 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. | 1096 | // Salt renders rainbow-tables attacks useless. |
1123 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1097 | $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); |
1098 | $conf->set('credentials.hash', sha1($_POST['setpassword'] . $conf->get('credentials.login') . $conf->get('credentials.salt'))); | ||
1124 | try { | 1099 | try { |
1125 | writeConfig($GLOBALS, isLoggedIn()); | 1100 | $conf->write(isLoggedIn()); |
1126 | } | 1101 | } |
1127 | catch(Exception $e) { | 1102 | catch(Exception $e) { |
1128 | error_log( | 1103 | error_log( |
@@ -1139,7 +1114,6 @@ function renderPage() | |||
1139 | } | 1114 | } |
1140 | else // show the change password form. | 1115 | else // show the change password form. |
1141 | { | 1116 | { |
1142 | $PAGE->assign('token',getToken()); | ||
1143 | $PAGE->renderPage('changepassword'); | 1117 | $PAGE->renderPage('changepassword'); |
1144 | exit; | 1118 | exit; |
1145 | } | 1119 | } |
@@ -1159,17 +1133,17 @@ function renderPage() | |||
1159 | ) { | 1133 | ) { |
1160 | $tz = $_POST['continent'] . '/' . $_POST['city']; | 1134 | $tz = $_POST['continent'] . '/' . $_POST['city']; |
1161 | } | 1135 | } |
1162 | $GLOBALS['timezone'] = $tz; | 1136 | $conf->set('general.timezone', $tz); |
1163 | $GLOBALS['title']=$_POST['title']; | 1137 | $conf->set('general.title', escape($_POST['title'])); |
1164 | $GLOBALS['titleLink']=$_POST['titleLink']; | 1138 | $conf->set('general.header_link', escape($_POST['titleLink'])); |
1165 | $GLOBALS['redirector']=$_POST['redirector']; | 1139 | $conf->set('redirector.url', escape($_POST['redirector'])); |
1166 | $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']); | 1140 | $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); |
1167 | $GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']); | 1141 | $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); |
1168 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']); | 1142 | $conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks'])); |
1169 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); | 1143 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); |
1170 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = !empty($_POST['hidePublicLinks']); | 1144 | $conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks'])); |
1171 | try { | 1145 | try { |
1172 | writeConfig($GLOBALS, isLoggedIn()); | 1146 | $conf->write(isLoggedIn()); |
1173 | } | 1147 | } |
1174 | catch(Exception $e) { | 1148 | catch(Exception $e) { |
1175 | error_log( | 1149 | error_log( |
@@ -1178,20 +1152,24 @@ function renderPage() | |||
1178 | ); | 1152 | ); |
1179 | 1153 | ||
1180 | // TODO: do not handle exceptions/errors in JS. | 1154 | // TODO: do not handle exceptions/errors in JS. |
1181 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>'; | 1155 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=configure\';</script>'; |
1182 | exit; | 1156 | exit; |
1183 | } | 1157 | } |
1184 | echo '<script>alert("Configuration was saved.");document.location=\'?do=tools\';</script>'; | 1158 | echo '<script>alert("Configuration was saved.");document.location=\'?do=configure\';</script>'; |
1185 | exit; | 1159 | exit; |
1186 | } | 1160 | } |
1187 | else // Show the configuration form. | 1161 | else // Show the configuration form. |
1188 | { | 1162 | { |
1189 | $PAGE->assign('token',getToken()); | 1163 | $PAGE->assign('title', $conf->get('general.title')); |
1190 | $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] ); | 1164 | $PAGE->assign('redirector', $conf->get('redirector.url')); |
1191 | $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] ); | 1165 | list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone')); |
1192 | list($timezone_form, $timezone_js) = generateTimeZoneForm($GLOBALS['timezone']); | ||
1193 | $PAGE->assign('timezone_form', $timezone_form); | 1166 | $PAGE->assign('timezone_form', $timezone_form); |
1194 | $PAGE->assign('timezone_js',$timezone_js); | 1167 | $PAGE->assign('timezone_js',$timezone_js); |
1168 | $PAGE->assign('private_links_default', $conf->get('privacy.default_private_links', false)); | ||
1169 | $PAGE->assign('session_protection_disabled', $conf->get('security.session_protection_disabled', false)); | ||
1170 | $PAGE->assign('enable_rss_permalinks', $conf->get('feed.rss_permalinks', false)); | ||
1171 | $PAGE->assign('enable_update_check', $conf->get('updates.check_updates', true)); | ||
1172 | $PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false)); | ||
1195 | $PAGE->renderPage('configure'); | 1173 | $PAGE->renderPage('configure'); |
1196 | exit; | 1174 | exit; |
1197 | } | 1175 | } |
@@ -1201,7 +1179,6 @@ function renderPage() | |||
1201 | if ($targetPage == Router::$PAGE_CHANGETAG) | 1179 | if ($targetPage == Router::$PAGE_CHANGETAG) |
1202 | { | 1180 | { |
1203 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { | 1181 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { |
1204 | $PAGE->assign('token', getToken()); | ||
1205 | $PAGE->assign('tags', $LINKSDB->allTags()); | 1182 | $PAGE->assign('tags', $LINKSDB->allTags()); |
1206 | $PAGE->renderPage('changetag'); | 1183 | $PAGE->renderPage('changetag'); |
1207 | exit; | 1184 | exit; |
@@ -1223,7 +1200,7 @@ function renderPage() | |||
1223 | $value['tags']=trim(implode(' ',$tags)); | 1200 | $value['tags']=trim(implode(' ',$tags)); |
1224 | $LINKSDB[$key]=$value; | 1201 | $LINKSDB[$key]=$value; |
1225 | } | 1202 | } |
1226 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); | 1203 | $LINKSDB->save($conf->get('resource.page_cache')); |
1227 | echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>'; | 1204 | echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>'; |
1228 | exit; | 1205 | exit; |
1229 | } | 1206 | } |
@@ -1240,7 +1217,7 @@ function renderPage() | |||
1240 | $value['tags']=trim(implode(' ',$tags)); | 1217 | $value['tags']=trim(implode(' ',$tags)); |
1241 | $LINKSDB[$key]=$value; | 1218 | $LINKSDB[$key]=$value; |
1242 | } | 1219 | } |
1243 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk. | 1220 | $LINKSDB->save($conf->get('resource.page_cache')); // Save to disk. |
1244 | echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>'; | 1221 | echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>'; |
1245 | exit; | 1222 | exit; |
1246 | } | 1223 | } |
@@ -1260,13 +1237,33 @@ function renderPage() | |||
1260 | if (! tokenOk($_POST['token'])) { | 1237 | if (! tokenOk($_POST['token'])) { |
1261 | die('Wrong token.'); | 1238 | die('Wrong token.'); |
1262 | } | 1239 | } |
1240 | |||
1241 | // lf_id should only be present if the link exists. | ||
1242 | $id = !empty($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : $LINKSDB->getNextId(); | ||
1243 | // Linkdate is kept here to: | ||
1244 | // - use the same permalink for notes as they're displayed when creating them | ||
1245 | // - let users hack creation date of their posts | ||
1246 | // See: https://github.com/shaarli/Shaarli/wiki/Datastore-hacks#changing-the-timestamp-for-a-link | ||
1247 | $linkdate = escape($_POST['lf_linkdate']); | ||
1248 | if (isset($LINKSDB[$id])) { | ||
1249 | // Edit | ||
1250 | $created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate); | ||
1251 | $updated = new DateTime(); | ||
1252 | $shortUrl = $LINKSDB[$id]['shorturl']; | ||
1253 | } else { | ||
1254 | // New link | ||
1255 | $created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate); | ||
1256 | $updated = null; | ||
1257 | $shortUrl = link_small_hash($created, $id); | ||
1258 | } | ||
1259 | |||
1263 | // Remove multiple spaces. | 1260 | // Remove multiple spaces. |
1264 | $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); | 1261 | $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); |
1265 | // Remove first '-' char in tags. | 1262 | // Remove first '-' char in tags. |
1266 | $tags = preg_replace('/(^| )\-/', '$1', $tags); | 1263 | $tags = preg_replace('/(^| )\-/', '$1', $tags); |
1267 | // Remove duplicates. | 1264 | // Remove duplicates. |
1268 | $tags = implode(' ', array_unique(explode(' ', $tags))); | 1265 | $tags = implode(' ', array_unique(explode(' ', $tags))); |
1269 | $linkdate = $_POST['lf_linkdate']; | 1266 | |
1270 | $url = trim($_POST['lf_url']); | 1267 | $url = trim($_POST['lf_url']); |
1271 | if (! startsWith($url, 'http:') && ! startsWith($url, 'https:') | 1268 | if (! startsWith($url, 'http:') && ! startsWith($url, 'https:') |
1272 | && ! startsWith($url, 'ftp:') && ! startsWith($url, 'magnet:') | 1269 | && ! startsWith($url, 'ftp:') && ! startsWith($url, 'magnet:') |
@@ -1276,13 +1273,17 @@ function renderPage() | |||
1276 | } | 1273 | } |
1277 | 1274 | ||
1278 | $link = array( | 1275 | $link = array( |
1276 | 'id' => $id, | ||
1279 | 'title' => trim($_POST['lf_title']), | 1277 | 'title' => trim($_POST['lf_title']), |
1280 | 'url' => $url, | 1278 | 'url' => $url, |
1281 | 'description' => $_POST['lf_description'], | 1279 | 'description' => $_POST['lf_description'], |
1282 | 'private' => (isset($_POST['lf_private']) ? 1 : 0), | 1280 | 'private' => (isset($_POST['lf_private']) ? 1 : 0), |
1283 | 'linkdate' => $linkdate, | 1281 | 'created' => $created, |
1284 | 'tags' => str_replace(',', ' ', $tags) | 1282 | 'updated' => $updated, |
1283 | 'tags' => str_replace(',', ' ', $tags), | ||
1284 | 'shorturl' => $shortUrl, | ||
1285 | ); | 1285 | ); |
1286 | |||
1286 | // If title is empty, use the URL as title. | 1287 | // If title is empty, use the URL as title. |
1287 | if ($link['title'] == '') { | 1288 | if ($link['title'] == '') { |
1288 | $link['title'] = $link['url']; | 1289 | $link['title'] = $link['url']; |
@@ -1290,9 +1291,9 @@ function renderPage() | |||
1290 | 1291 | ||
1291 | $pluginManager->executeHooks('save_link', $link); | 1292 | $pluginManager->executeHooks('save_link', $link); |
1292 | 1293 | ||
1293 | $LINKSDB[$linkdate] = $link; | 1294 | $LINKSDB[$id] = $link; |
1294 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); | 1295 | $LINKSDB->save($conf->get('resource.page_cache')); |
1295 | pubsubhub(); | 1296 | pubsubhub($conf); |
1296 | 1297 | ||
1297 | // If we are called from the bookmarklet, we must close the popup: | 1298 | // If we are called from the bookmarklet, we must close the popup: |
1298 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { | 1299 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { |
@@ -1303,7 +1304,7 @@ function renderPage() | |||
1303 | $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?'; | 1304 | $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?'; |
1304 | $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); | 1305 | $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); |
1305 | // Scroll to the link which has been edited. | 1306 | // Scroll to the link which has been edited. |
1306 | $location .= '#' . smallHash($_POST['lf_linkdate']); | 1307 | $location .= '#' . $link['shorturl']; |
1307 | // After saving the link, redirect to the page the user was on. | 1308 | // After saving the link, redirect to the page the user was on. |
1308 | header('Location: '. $location); | 1309 | header('Location: '. $location); |
1309 | exit; | 1310 | exit; |
@@ -1314,8 +1315,10 @@ function renderPage() | |||
1314 | { | 1315 | { |
1315 | // If we are called from the bookmarklet, we must close the popup: | 1316 | // If we are called from the bookmarklet, we must close the popup: |
1316 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1317 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } |
1318 | $link = $LINKSDB[(int) escape($_POST['lf_id'])]; | ||
1317 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); | 1319 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); |
1318 | $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. | 1320 | // Scroll to the link which has been edited. |
1321 | $returnurl .= '#'. $link['shorturl']; | ||
1319 | $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); | 1322 | $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); |
1320 | header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. | 1323 | header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. |
1321 | exit; | 1324 | exit; |
@@ -1325,15 +1328,18 @@ function renderPage() | |||
1325 | if (isset($_POST['delete_link'])) | 1328 | if (isset($_POST['delete_link'])) |
1326 | { | 1329 | { |
1327 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | 1330 | if (!tokenOk($_POST['token'])) die('Wrong token.'); |
1331 | |||
1328 | // We do not need to ask for confirmation: | 1332 | // We do not need to ask for confirmation: |
1329 | // - confirmation is handled by JavaScript | 1333 | // - confirmation is handled by JavaScript |
1330 | // - we are protected from XSRF by the token. | 1334 | // - we are protected from XSRF by the token. |
1331 | $linkdate=$_POST['lf_linkdate']; | ||
1332 | 1335 | ||
1333 | $pluginManager->executeHooks('delete_link', $LINKSDB[$linkdate]); | 1336 | // FIXME! We keep `lf_linkdate` for consistency before a proper API. To be removed. |
1337 | $id = isset($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : intval(escape($_POST['lf_linkdate'])); | ||
1338 | |||
1339 | $pluginManager->executeHooks('delete_link', $LINKSDB[$id]); | ||
1334 | 1340 | ||
1335 | unset($LINKSDB[$linkdate]); | 1341 | unset($LINKSDB[$id]); |
1336 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // save to disk | 1342 | $LINKSDB->save('resource.page_cache'); // save to disk |
1337 | 1343 | ||
1338 | // If we are called from the bookmarklet, we must close the popup: | 1344 | // If we are called from the bookmarklet, we must close the popup: |
1339 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1345 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } |
@@ -1371,12 +1377,13 @@ function renderPage() | |||
1371 | // -------- User clicked the "EDIT" button on a link: Display link edit form. | 1377 | // -------- User clicked the "EDIT" button on a link: Display link edit form. |
1372 | if (isset($_GET['edit_link'])) | 1378 | if (isset($_GET['edit_link'])) |
1373 | { | 1379 | { |
1374 | $link = $LINKSDB[$_GET['edit_link']]; // Read database | 1380 | $id = (int) escape($_GET['edit_link']); |
1381 | $link = $LINKSDB[$id]; // Read database | ||
1375 | if (!$link) { header('Location: ?'); exit; } // Link not found in database. | 1382 | if (!$link) { header('Location: ?'); exit; } // Link not found in database. |
1383 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); | ||
1376 | $data = array( | 1384 | $data = array( |
1377 | 'link' => $link, | 1385 | 'link' => $link, |
1378 | 'link_is_new' => false, | 1386 | 'link_is_new' => false, |
1379 | 'token' => getToken(), | ||
1380 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1387 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1381 | 'tags' => $LINKSDB->allTags(), | 1388 | 'tags' => $LINKSDB->allTags(), |
1382 | ); | 1389 | ); |
@@ -1397,10 +1404,10 @@ function renderPage() | |||
1397 | $link_is_new = false; | 1404 | $link_is_new = false; |
1398 | // Check if URL is not already in database (in this case, we will edit the existing link) | 1405 | // Check if URL is not already in database (in this case, we will edit the existing link) |
1399 | $link = $LINKSDB->getLinkFromUrl($url); | 1406 | $link = $LINKSDB->getLinkFromUrl($url); |
1400 | if (!$link) | 1407 | if (! $link) |
1401 | { | 1408 | { |
1402 | $link_is_new = true; | 1409 | $link_is_new = true; |
1403 | $linkdate = strval(date('Ymd_His')); | 1410 | $linkdate = strval(date(LinkDB::LINK_DATE_FORMAT)); |
1404 | // Get title if it was provided in URL (by the bookmarklet). | 1411 | // Get title if it was provided in URL (by the bookmarklet). |
1405 | $title = empty($_GET['title']) ? '' : escape($_GET['title']); | 1412 | $title = empty($_GET['title']) ? '' : escape($_GET['title']); |
1406 | // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] | 1413 | // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] |
@@ -1424,7 +1431,7 @@ function renderPage() | |||
1424 | } | 1431 | } |
1425 | 1432 | ||
1426 | if ($url == '') { | 1433 | if ($url == '') { |
1427 | $url = '?' . smallHash($linkdate); | 1434 | $url = '?' . smallHash($linkdate . $LINKSDB->getNextId()); |
1428 | $title = 'Note: '; | 1435 | $title = 'Note: '; |
1429 | } | 1436 | } |
1430 | $url = escape($url); | 1437 | $url = escape($url); |
@@ -1438,15 +1445,17 @@ function renderPage() | |||
1438 | 'tags' => $tags, | 1445 | 'tags' => $tags, |
1439 | 'private' => $private | 1446 | 'private' => $private |
1440 | ); | 1447 | ); |
1448 | } else { | ||
1449 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); | ||
1441 | } | 1450 | } |
1442 | 1451 | ||
1443 | $data = array( | 1452 | $data = array( |
1444 | 'link' => $link, | 1453 | 'link' => $link, |
1445 | 'link_is_new' => $link_is_new, | 1454 | 'link_is_new' => $link_is_new, |
1446 | 'token' => getToken(), // XSRF protection. | ||
1447 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1455 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1448 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), | 1456 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), |
1449 | 'tags' => $LINKSDB->allTags(), | 1457 | 'tags' => $LINKSDB->allTags(), |
1458 | 'default_private_links' => $conf->get('privacy.default_private_links', false), | ||
1450 | ); | 1459 | ); |
1451 | $pluginManager->executeHooks('render_editlink', $data); | 1460 | $pluginManager->executeHooks('render_editlink', $data); |
1452 | 1461 | ||
@@ -1502,27 +1511,37 @@ function renderPage() | |||
1502 | exit; | 1511 | exit; |
1503 | } | 1512 | } |
1504 | 1513 | ||
1505 | // -------- User is uploading a file for import | 1514 | if ($targetPage == Router::$PAGE_IMPORT) { |
1506 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=upload')) | 1515 | // Upload a Netscape bookmark dump to import its contents |
1507 | { | 1516 | |
1508 | // If file is too big, some form field may be missing. | 1517 | if (! isset($_POST['token']) || ! isset($_FILES['filetoupload'])) { |
1509 | if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) | 1518 | // Show import dialog |
1510 | { | 1519 | $PAGE->assign('maxfilesize', getMaxFileSize()); |
1511 | $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); | 1520 | $PAGE->renderPage('import'); |
1512 | echo '<script>alert("The file you are trying to upload is probably bigger than what this webserver can accept ('.getMaxFileSize().' bytes). Please upload in smaller chunks.");document.location=\''.escape($returnurl).'\';</script>'; | ||
1513 | exit; | 1521 | exit; |
1514 | } | 1522 | } |
1515 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | ||
1516 | importFile($LINKSDB); | ||
1517 | exit; | ||
1518 | } | ||
1519 | 1523 | ||
1520 | // -------- Show upload/import dialog: | 1524 | // Import bookmarks from an uploaded file |
1521 | if ($targetPage == Router::$PAGE_IMPORT) | 1525 | if (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size'] == 0) { |
1522 | { | 1526 | // The file is too big or some form field may be missing. |
1523 | $PAGE->assign('token',getToken()); | 1527 | echo '<script>alert("The file you are trying to upload is probably' |
1524 | $PAGE->assign('maxfilesize',getMaxFileSize()); | 1528 | .' bigger than what this webserver can accept (' |
1525 | $PAGE->renderPage('import'); | 1529 | .getMaxFileSize().' bytes).' |
1530 | .' Please upload in smaller chunks.");document.location=\'?do=' | ||
1531 | .Router::$PAGE_IMPORT .'\';</script>'; | ||
1532 | exit; | ||
1533 | } | ||
1534 | if (! tokenOk($_POST['token'])) { | ||
1535 | die('Wrong token.'); | ||
1536 | } | ||
1537 | $status = NetscapeBookmarkUtils::import( | ||
1538 | $_POST, | ||
1539 | $_FILES, | ||
1540 | $LINKSDB, | ||
1541 | $conf->get('resource.page_cache') | ||
1542 | ); | ||
1543 | echo '<script>alert("'.$status.'");document.location=\'?do=' | ||
1544 | .Router::$PAGE_IMPORT .'\';</script>'; | ||
1526 | exit; | 1545 | exit; |
1527 | } | 1546 | } |
1528 | 1547 | ||
@@ -1533,7 +1552,7 @@ function renderPage() | |||
1533 | // Split plugins into 2 arrays: ordered enabled plugins and disabled. | 1552 | // Split plugins into 2 arrays: ordered enabled plugins and disabled. |
1534 | $enabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] !== false; }); | 1553 | $enabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] !== false; }); |
1535 | // Load parameters. | 1554 | // Load parameters. |
1536 | $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $GLOBALS['plugins']); | 1555 | $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $conf->get('plugins', array())); |
1537 | uasort( | 1556 | uasort( |
1538 | $enabledPlugins, | 1557 | $enabledPlugins, |
1539 | function($a, $b) { return $a['order'] - $b['order']; } | 1558 | function($a, $b) { return $a['order'] - $b['order']; } |
@@ -1552,13 +1571,13 @@ function renderPage() | |||
1552 | if (isset($_POST['parameters_form'])) { | 1571 | if (isset($_POST['parameters_form'])) { |
1553 | unset($_POST['parameters_form']); | 1572 | unset($_POST['parameters_form']); |
1554 | foreach ($_POST as $param => $value) { | 1573 | foreach ($_POST as $param => $value) { |
1555 | $GLOBALS['plugins'][$param] = escape($value); | 1574 | $conf->set('plugins.'. $param, escape($value)); |
1556 | } | 1575 | } |
1557 | } | 1576 | } |
1558 | else { | 1577 | else { |
1559 | $GLOBALS['config']['ENABLED_PLUGINS'] = save_plugin_config($_POST); | 1578 | $conf->set('general.enabled_plugins', save_plugin_config($_POST)); |
1560 | } | 1579 | } |
1561 | writeConfig($GLOBALS, isLoggedIn()); | 1580 | $conf->write(isLoggedIn()); |
1562 | } | 1581 | } |
1563 | catch (Exception $e) { | 1582 | catch (Exception $e) { |
1564 | error_log( | 1583 | error_log( |
@@ -1575,103 +1594,20 @@ function renderPage() | |||
1575 | } | 1594 | } |
1576 | 1595 | ||
1577 | // -------- Otherwise, simply display search form and links: | 1596 | // -------- Otherwise, simply display search form and links: |
1578 | showLinkList($PAGE, $LINKSDB); | 1597 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); |
1579 | exit; | 1598 | exit; |
1580 | } | 1599 | } |
1581 | 1600 | ||
1582 | // ----------------------------------------------------------------------------------------------- | ||
1583 | // Process the import file form. | ||
1584 | function importFile($LINKSDB) | ||
1585 | { | ||
1586 | if (!isLoggedIn()) { die('Not allowed.'); } | ||
1587 | |||
1588 | $filename=$_FILES['filetoupload']['name']; | ||
1589 | $filesize=$_FILES['filetoupload']['size']; | ||
1590 | $data=file_get_contents($_FILES['filetoupload']['tmp_name']); | ||
1591 | $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private? | ||
1592 | $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones? | ||
1593 | $import_count=0; | ||
1594 | |||
1595 | // Sniff file type: | ||
1596 | $type='unknown'; | ||
1597 | if (startsWith($data,'<!DOCTYPE NETSCAPE-Bookmark-file-1>')) $type='netscape'; // Netscape bookmark file (aka Firefox). | ||
1598 | |||
1599 | // Then import the bookmarks. | ||
1600 | if ($type=='netscape') | ||
1601 | { | ||
1602 | // This is a standard Netscape-style bookmark file. | ||
1603 | // This format is supported by all browsers (except IE, of course), also Delicious, Diigo and others. | ||
1604 | foreach(explode('<DT>',$data) as $html) // explode is very fast | ||
1605 | { | ||
1606 | $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); | ||
1607 | $d = explode('<DD>',$html); | ||
1608 | if (startsWith($d[0], '<A ')) | ||
1609 | { | ||
1610 | $link['description'] = (isset($d[1]) ? html_entity_decode(trim($d[1]),ENT_QUOTES,'UTF-8') : ''); // Get description (optional) | ||
1611 | preg_match('!<A .*?>(.*?)</A>!i',$d[0],$matches); $link['title'] = (isset($matches[1]) ? trim($matches[1]) : ''); // Get title | ||
1612 | $link['title'] = html_entity_decode($link['title'],ENT_QUOTES,'UTF-8'); | ||
1613 | preg_match_all('! ([A-Z_]+)=\"(.*?)"!i',$html,$matches,PREG_SET_ORDER); // Get all other attributes | ||
1614 | $raw_add_date=0; | ||
1615 | foreach($matches as $m) | ||
1616 | { | ||
1617 | $attr=$m[1]; $value=$m[2]; | ||
1618 | if ($attr=='HREF') $link['url']=html_entity_decode($value,ENT_QUOTES,'UTF-8'); | ||
1619 | elseif ($attr=='ADD_DATE') | ||
1620 | { | ||
1621 | $raw_add_date=intval($value); | ||
1622 | if ($raw_add_date>30000000000) $raw_add_date/=1000; //If larger than year 2920, then was likely stored in milliseconds instead of seconds | ||
1623 | } | ||
1624 | elseif ($attr=='PRIVATE') $link['private']=($value=='0'?0:1); | ||
1625 | elseif ($attr=='TAGS') $link['tags']=html_entity_decode(str_replace(',',' ',$value),ENT_QUOTES,'UTF-8'); | ||
1626 | } | ||
1627 | if ($link['url']!='') | ||
1628 | { | ||
1629 | if ($private==1) $link['private']=1; | ||
1630 | $dblink = $LINKSDB->getLinkFromUrl($link['url']); // See if the link is already in database. | ||
1631 | if ($dblink==false) | ||
1632 | { // Link not in database, let's import it... | ||
1633 | if (empty($raw_add_date)) $raw_add_date=time(); // In case of shitty bookmark file with no ADD_DATE | ||
1634 | |||
1635 | // Make sure date/time is not already used by another link. | ||
1636 | // (Some bookmark files have several different links with the same ADD_DATE) | ||
1637 | // We increment date by 1 second until we find a date which is not used in DB. | ||
1638 | // (so that links that have the same date/time are more or less kept grouped by date, but do not conflict.) | ||
1639 | while (!empty($LINKSDB[date('Ymd_His',$raw_add_date)])) { $raw_add_date++; }// Yes, I know it's ugly. | ||
1640 | $link['linkdate']=date('Ymd_His',$raw_add_date); | ||
1641 | $LINKSDB[$link['linkdate']] = $link; | ||
1642 | $import_count++; | ||
1643 | } | ||
1644 | else // Link already present in database. | ||
1645 | { | ||
1646 | if ($overwrite) | ||
1647 | { // If overwrite is required, we import link data, except date/time. | ||
1648 | $link['linkdate']=$dblink['linkdate']; | ||
1649 | $LINKSDB[$link['linkdate']] = $link; | ||
1650 | $import_count++; | ||
1651 | } | ||
1652 | } | ||
1653 | |||
1654 | } | ||
1655 | } | ||
1656 | } | ||
1657 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); | ||
1658 | |||
1659 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) was successfully processed: '.$import_count.' links imported.");document.location=\'?\';</script>'; | ||
1660 | } | ||
1661 | else | ||
1662 | { | ||
1663 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) has an unknown file format. Nothing was imported.");document.location=\'?\';</script>'; | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | /** | 1601 | /** |
1668 | * Template for the list of links (<div id="linklist">) | 1602 | * Template for the list of links (<div id="linklist">) |
1669 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' | 1603 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' |
1670 | * | 1604 | * |
1671 | * @param pageBuilder $PAGE pageBuilder instance. | 1605 | * @param pageBuilder $PAGE pageBuilder instance. |
1672 | * @param LinkDB $LINKSDB LinkDB instance. | 1606 | * @param LinkDB $LINKSDB LinkDB instance. |
1607 | * @param ConfigManager $conf Configuration Manager instance. | ||
1608 | * @param PluginManager $pluginManager Plugin Manager instance. | ||
1673 | */ | 1609 | */ |
1674 | function buildLinkList($PAGE,$LINKSDB) | 1610 | function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) |
1675 | { | 1611 | { |
1676 | // Used in templates | 1612 | // Used in templates |
1677 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; | 1613 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; |
@@ -1698,10 +1634,7 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1698 | $keys[] = $key; | 1634 | $keys[] = $key; |
1699 | } | 1635 | } |
1700 | 1636 | ||
1701 | // If there is only a single link, we change on-the-fly the title of the page. | 1637 | |
1702 | if (count($linksToDisplay) == 1) { | ||
1703 | $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; | ||
1704 | } | ||
1705 | 1638 | ||
1706 | // Select articles according to paging. | 1639 | // Select articles according to paging. |
1707 | $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']); | 1640 | $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']); |
@@ -1716,15 +1649,18 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1716 | while ($i<$end && $i<count($keys)) | 1649 | while ($i<$end && $i<count($keys)) |
1717 | { | 1650 | { |
1718 | $link = $linksToDisplay[$keys[$i]]; | 1651 | $link = $linksToDisplay[$keys[$i]]; |
1719 | $link['description'] = format_description($link['description'], $GLOBALS['redirector']); | 1652 | $link['description'] = format_description($link['description'], $conf->get('redirector.url')); |
1720 | $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; | 1653 | $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; |
1721 | $link['class'] = $link['private'] == 0 ? $classLi : 'private'; | 1654 | $link['class'] = $link['private'] == 0 ? $classLi : 'private'; |
1722 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 1655 | $link['timestamp'] = $link['created']->getTimestamp(); |
1723 | $link['timestamp'] = $date->getTimestamp(); | 1656 | if (! empty($link['updated'])) { |
1657 | $link['updated_timestamp'] = $link['updated']->getTimestamp(); | ||
1658 | } else { | ||
1659 | $link['updated_timestamp'] = ''; | ||
1660 | } | ||
1724 | $taglist = explode(' ', $link['tags']); | 1661 | $taglist = explode(' ', $link['tags']); |
1725 | uasort($taglist, 'strcasecmp'); | 1662 | uasort($taglist, 'strcasecmp'); |
1726 | $link['taglist'] = $taglist; | 1663 | $link['taglist'] = $taglist; |
1727 | $link['shorturl'] = smallHash($link['linkdate']); | ||
1728 | // Check for both signs of a note: starting with ? and 7 chars long. | 1664 | // Check for both signs of a note: starting with ? and 7 chars long. |
1729 | if ($link['url'][0] === '?' && | 1665 | if ($link['url'][0] === '?' && |
1730 | strlen($link['url']) === 7) { | 1666 | strlen($link['url']) === 7) { |
@@ -1747,8 +1683,6 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1747 | $next_page_url = '?page=' . ($page-1) . $searchtermUrl . $searchtagsUrl; | 1683 | $next_page_url = '?page=' . ($page-1) . $searchtermUrl . $searchtagsUrl; |
1748 | } | 1684 | } |
1749 | 1685 | ||
1750 | $token = isLoggedIn() ? getToken() : ''; | ||
1751 | |||
1752 | // Fill all template fields. | 1686 | // Fill all template fields. |
1753 | $data = array( | 1687 | $data = array( |
1754 | 'previous_page_url' => $previous_page_url, | 1688 | 'previous_page_url' => $previous_page_url, |
@@ -1758,17 +1692,16 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1758 | 'result_count' => count($linksToDisplay), | 1692 | 'result_count' => count($linksToDisplay), |
1759 | 'search_term' => $searchterm, | 1693 | 'search_term' => $searchterm, |
1760 | 'search_tags' => $searchtags, | 1694 | 'search_tags' => $searchtags, |
1761 | 'redirector' => empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'], // Optional redirector URL. | 1695 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. |
1762 | 'token' => $token, | ||
1763 | 'links' => $linkDisp, | 1696 | 'links' => $linkDisp, |
1764 | 'tags' => $LINKSDB->allTags(), | 1697 | 'tags' => $LINKSDB->allTags(), |
1765 | ); | 1698 | ); |
1766 | // FIXME! temporary fix - see #399. | 1699 | |
1767 | if (!empty($GLOBALS['pagetitle']) && count($linkDisp) == 1) { | 1700 | // If there is only a single link, we change on-the-fly the title of the page. |
1768 | $data['pagetitle'] = $GLOBALS['pagetitle']; | 1701 | if (count($linksToDisplay) == 1) { |
1702 | $data['pagetitle'] = $linksToDisplay[$keys[0]]['title'] .' - '. $conf->get('general.title'); | ||
1769 | } | 1703 | } |
1770 | 1704 | ||
1771 | $pluginManager = PluginManager::getInstance(); | ||
1772 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); | 1705 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); |
1773 | 1706 | ||
1774 | foreach ($data as $key => $value) { | 1707 | foreach ($data as $key => $value) { |
@@ -1778,18 +1711,26 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1778 | return; | 1711 | return; |
1779 | } | 1712 | } |
1780 | 1713 | ||
1781 | // Compute the thumbnail for a link. | 1714 | /** |
1782 | // | 1715 | * Compute the thumbnail for a link. |
1783 | // With a link to the original URL. | 1716 | * |
1784 | // Understands various services (youtube.com...) | 1717 | * With a link to the original URL. |
1785 | // Input: $url = URL for which the thumbnail must be found. | 1718 | * Understands various services (youtube.com...) |
1786 | // $href = if provided, this URL will be followed instead of $url | 1719 | * Input: $url = URL for which the thumbnail must be found. |
1787 | // Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) | 1720 | * $href = if provided, this URL will be followed instead of $url |
1788 | // Some of them may be missing. | 1721 | * Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) |
1789 | // Return an empty array if no thumbnail available. | 1722 | * Some of them may be missing. |
1790 | function computeThumbnail($url,$href=false) | 1723 | * Return an empty array if no thumbnail available. |
1724 | * | ||
1725 | * @param ConfigManager $conf Configuration Manager instance. | ||
1726 | * @param string $url | ||
1727 | * @param string|bool $href | ||
1728 | * | ||
1729 | * @return array | ||
1730 | */ | ||
1731 | function computeThumbnail($conf, $url, $href = false) | ||
1791 | { | 1732 | { |
1792 | if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return array(); | 1733 | if (!$conf->get('thumbnail.enable_thumbnails')) return array(); |
1793 | if ($href==false) $href=$url; | 1734 | if ($href==false) $href=$url; |
1794 | 1735 | ||
1795 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. | 1736 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. |
@@ -1857,7 +1798,7 @@ function computeThumbnail($url,$href=false) | |||
1857 | // So we deport the thumbnail generation in order not to slow down page generation | 1798 | // So we deport the thumbnail generation in order not to slow down page generation |
1858 | // (and we also cache the thumbnail) | 1799 | // (and we also cache the thumbnail) |
1859 | 1800 | ||
1860 | if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache. | 1801 | if (! $conf->get('thumbnail.enable_localcache')) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache. |
1861 | 1802 | ||
1862 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') | 1803 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') |
1863 | || $domain=='vimeo.com' | 1804 | || $domain=='vimeo.com' |
@@ -1880,7 +1821,7 @@ function computeThumbnail($url,$href=false) | |||
1880 | $path = parse_url($url,PHP_URL_PATH); | 1821 | $path = parse_url($url,PHP_URL_PATH); |
1881 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. | 1822 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. |
1882 | } | 1823 | } |
1883 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) | 1824 | $sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation) |
1884 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | 1825 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), |
1885 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | 1826 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); |
1886 | } | 1827 | } |
@@ -1891,7 +1832,7 @@ function computeThumbnail($url,$href=false) | |||
1891 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); | 1832 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); |
1892 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') | 1833 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') |
1893 | { | 1834 | { |
1894 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) | 1835 | $sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation) |
1895 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | 1836 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), |
1896 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | 1837 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); |
1897 | } | 1838 | } |
@@ -1908,7 +1849,9 @@ function computeThumbnail($url,$href=false) | |||
1908 | // Returns '' if no thumbnail available. | 1849 | // Returns '' if no thumbnail available. |
1909 | function thumbnail($url,$href=false) | 1850 | function thumbnail($url,$href=false) |
1910 | { | 1851 | { |
1911 | $t = computeThumbnail($url,$href); | 1852 | // FIXME! |
1853 | global $conf; | ||
1854 | $t = computeThumbnail($conf, $url,$href); | ||
1912 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | 1855 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. |
1913 | 1856 | ||
1914 | $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"'; | 1857 | $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"'; |
@@ -1926,9 +1869,11 @@ function thumbnail($url,$href=false) | |||
1926 | // Input: $url = URL for which the thumbnail must be found. | 1869 | // Input: $url = URL for which the thumbnail must be found. |
1927 | // $href = if provided, this URL will be followed instead of $url | 1870 | // $href = if provided, this URL will be followed instead of $url |
1928 | // Returns '' if no thumbnail available. | 1871 | // Returns '' if no thumbnail available. |
1929 | function lazyThumbnail($url,$href=false) | 1872 | function lazyThumbnail($conf, $url,$href=false) |
1930 | { | 1873 | { |
1931 | $t = computeThumbnail($url,$href); | 1874 | // FIXME! |
1875 | global $conf; | ||
1876 | $t = computeThumbnail($conf, $url,$href); | ||
1932 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | 1877 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. |
1933 | 1878 | ||
1934 | $html='<a href="'.escape($t['href']).'">'; | 1879 | $html='<a href="'.escape($t['href']).'">'; |
@@ -1954,10 +1899,13 @@ function lazyThumbnail($url,$href=false) | |||
1954 | } | 1899 | } |
1955 | 1900 | ||
1956 | 1901 | ||
1957 | // ----------------------------------------------------------------------------------------------- | 1902 | /** |
1958 | // Installation | 1903 | * Installation |
1959 | // This function should NEVER be called if the file data/config.php exists. | 1904 | * This function should NEVER be called if the file data/config.php exists. |
1960 | function install() | 1905 | * |
1906 | * @param ConfigManager $conf Configuration Manager instance. | ||
1907 | */ | ||
1908 | function install($conf) | ||
1961 | { | 1909 | { |
1962 | // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. | 1910 | // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. |
1963 | if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); | 1911 | if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); |
@@ -1994,15 +1942,21 @@ function install() | |||
1994 | ) { | 1942 | ) { |
1995 | $tz = $_POST['continent'].'/'.$_POST['city']; | 1943 | $tz = $_POST['continent'].'/'.$_POST['city']; |
1996 | } | 1944 | } |
1997 | $GLOBALS['timezone'] = $tz; | 1945 | $conf->set('general.timezone', $tz); |
1998 | // Everything is ok, let's create config file. | 1946 | $login = $_POST['setlogin']; |
1999 | $GLOBALS['login'] = $_POST['setlogin']; | 1947 | $conf->set('credentials.login', $login); |
2000 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. | 1948 | $salt = sha1(uniqid('', true) .'_'. mt_rand()); |
2001 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1949 | $conf->set('credentials.salt', $salt); |
2002 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(index_url($_SERVER)) : $_POST['title'] ); | 1950 | $conf->set('credentials.hash', sha1($_POST['setpassword'] . $login . $salt)); |
2003 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); | 1951 | if (!empty($_POST['title'])) { |
1952 | $conf->set('general.title', escape($_POST['title'])); | ||
1953 | } else { | ||
1954 | $conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER))); | ||
1955 | } | ||
1956 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); | ||
2004 | try { | 1957 | try { |
2005 | writeConfig($GLOBALS, isLoggedIn()); | 1958 | // Everything is ok, let's create config file. |
1959 | $conf->write(isLoggedIn()); | ||
2006 | } | 1960 | } |
2007 | catch(Exception $e) { | 1961 | catch(Exception $e) { |
2008 | error_log( | 1962 | error_log( |
@@ -2025,42 +1979,46 @@ function install() | |||
2025 | $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; | 1979 | $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; |
2026 | } | 1980 | } |
2027 | 1981 | ||
2028 | $PAGE = new PageBuilder(); | 1982 | $PAGE = new PageBuilder($conf); |
2029 | $PAGE->assign('timezone_html',$timezone_html); | 1983 | $PAGE->assign('timezone_html',$timezone_html); |
2030 | $PAGE->assign('timezone_js',$timezone_js); | 1984 | $PAGE->assign('timezone_js',$timezone_js); |
2031 | $PAGE->renderPage('install'); | 1985 | $PAGE->renderPage('install'); |
2032 | exit; | 1986 | exit; |
2033 | } | 1987 | } |
2034 | 1988 | ||
2035 | /* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, | 1989 | /** |
2036 | I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. | 1990 | * Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, |
2037 | The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail. | 1991 | * I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. |
2038 | This function is called by passing the URL: | 1992 | * The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail. |
2039 | http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] | 1993 | * This function is called by passing the URL: |
2040 | [URL] is the URL of the link (e.g. a flickr page) | 1994 | * http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] |
2041 | [HMAC] is the signature for the [URL] (so that these URL cannot be forged). | 1995 | * [URL] is the URL of the link (e.g. a flickr page) |
2042 | The function below will fetch the image from the webservice and store it in the cache. | 1996 | * [HMAC] is the signature for the [URL] (so that these URL cannot be forged). |
2043 | */ | 1997 | * The function below will fetch the image from the webservice and store it in the cache. |
2044 | function genThumbnail() | 1998 | * |
1999 | * @param ConfigManager $conf Configuration Manager instance, | ||
2000 | */ | ||
2001 | function genThumbnail($conf) | ||
2045 | { | 2002 | { |
2046 | // Make sure the parameters in the URL were generated by us. | 2003 | // Make sure the parameters in the URL were generated by us. |
2047 | $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']); | 2004 | $sign = hash_hmac('sha256', $_GET['url'], $conf->get('credentials.salt')); |
2048 | if ($sign!=$_GET['hmac']) die('Naughty boy!'); | 2005 | if ($sign!=$_GET['hmac']) die('Naughty boy!'); |
2049 | 2006 | ||
2007 | $cacheDir = $conf->get('resource.thumbnails_cache', 'cache'); | ||
2050 | // Let's see if we don't already have the image for this URL in the cache. | 2008 | // Let's see if we don't already have the image for this URL in the cache. |
2051 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; | 2009 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; |
2052 | if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$thumbname)) | 2010 | if (is_file($cacheDir .'/'. $thumbname)) |
2053 | { // We have the thumbnail, just serve it: | 2011 | { // We have the thumbnail, just serve it: |
2054 | header('Content-Type: image/jpeg'); | 2012 | header('Content-Type: image/jpeg'); |
2055 | echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname); | 2013 | echo file_get_contents($cacheDir .'/'. $thumbname); |
2056 | return; | 2014 | return; |
2057 | } | 2015 | } |
2058 | // We may also serve a blank image (if service did not respond) | 2016 | // We may also serve a blank image (if service did not respond) |
2059 | $blankname=hash('sha1',$_GET['url']).'.gif'; | 2017 | $blankname=hash('sha1',$_GET['url']).'.gif'; |
2060 | if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$blankname)) | 2018 | if (is_file($cacheDir .'/'. $blankname)) |
2061 | { | 2019 | { |
2062 | header('Content-Type: image/gif'); | 2020 | header('Content-Type: image/gif'); |
2063 | echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname); | 2021 | echo file_get_contents($cacheDir .'/'. $blankname); |
2064 | return; | 2022 | return; |
2065 | } | 2023 | } |
2066 | 2024 | ||
@@ -2107,7 +2065,7 @@ function genThumbnail() | |||
2107 | list($headers, $content) = get_http_response($imageurl, 10); | 2065 | list($headers, $content) = get_http_response($imageurl, 10); |
2108 | if (strpos($headers[0], '200 OK') !== false) { | 2066 | if (strpos($headers[0], '200 OK') !== false) { |
2109 | // Save image to cache. | 2067 | // Save image to cache. |
2110 | file_put_contents($GLOBALS['config']['CACHEDIR'].'/' . $thumbname, $content); | 2068 | file_put_contents($cacheDir .'/'. $thumbname, $content); |
2111 | header('Content-Type: image/jpeg'); | 2069 | header('Content-Type: image/jpeg'); |
2112 | echo $content; | 2070 | echo $content; |
2113 | return; | 2071 | return; |
@@ -2128,7 +2086,7 @@ function genThumbnail() | |||
2128 | list($headers, $content) = get_http_response($imageurl, 10); | 2086 | list($headers, $content) = get_http_response($imageurl, 10); |
2129 | if (strpos($headers[0], '200 OK') !== false) { | 2087 | if (strpos($headers[0], '200 OK') !== false) { |
2130 | // Save image to cache. | 2088 | // Save image to cache. |
2131 | file_put_contents($GLOBALS['config']['CACHEDIR'] . '/' . $thumbname, $content); | 2089 | file_put_contents($cacheDir .'/'. $thumbname, $content); |
2132 | header('Content-Type: image/jpeg'); | 2090 | header('Content-Type: image/jpeg'); |
2133 | echo $content; | 2091 | echo $content; |
2134 | return; | 2092 | return; |
@@ -2151,7 +2109,7 @@ function genThumbnail() | |||
2151 | // No control on image size, so wait long enough | 2109 | // No control on image size, so wait long enough |
2152 | list($headers, $content) = get_http_response($imageurl, 20); | 2110 | list($headers, $content) = get_http_response($imageurl, 20); |
2153 | if (strpos($headers[0], '200 OK') !== false) { | 2111 | if (strpos($headers[0], '200 OK') !== false) { |
2154 | $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; | 2112 | $filepath = $cacheDir .'/'. $thumbname; |
2155 | file_put_contents($filepath, $content); // Save image to cache. | 2113 | file_put_contents($filepath, $content); // Save image to cache. |
2156 | if (resizeImage($filepath)) | 2114 | if (resizeImage($filepath)) |
2157 | { | 2115 | { |
@@ -2179,7 +2137,7 @@ function genThumbnail() | |||
2179 | // No control on image size, so wait long enough | 2137 | // No control on image size, so wait long enough |
2180 | list($headers, $content) = get_http_response($imageurl, 20); | 2138 | list($headers, $content) = get_http_response($imageurl, 20); |
2181 | if (strpos($headers[0], '200 OK') !== false) { | 2139 | if (strpos($headers[0], '200 OK') !== false) { |
2182 | $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; | 2140 | $filepath = $cacheDir.'/'.$thumbname; |
2183 | // Save image to cache. | 2141 | // Save image to cache. |
2184 | file_put_contents($filepath, $content); | 2142 | file_put_contents($filepath, $content); |
2185 | if (resizeImage($filepath)) | 2143 | if (resizeImage($filepath)) |
@@ -2199,7 +2157,7 @@ function genThumbnail() | |||
2199 | // We allow 30 seconds max to download (and downloads are limited to 4 Mb) | 2157 | // We allow 30 seconds max to download (and downloads are limited to 4 Mb) |
2200 | list($headers, $content) = get_http_response($url, 30); | 2158 | list($headers, $content) = get_http_response($url, 30); |
2201 | if (strpos($headers[0], '200 OK') !== false) { | 2159 | if (strpos($headers[0], '200 OK') !== false) { |
2202 | $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; | 2160 | $filepath = $cacheDir .'/'.$thumbname; |
2203 | // Save image to cache. | 2161 | // Save image to cache. |
2204 | file_put_contents($filepath, $content); | 2162 | file_put_contents($filepath, $content); |
2205 | if (resizeImage($filepath)) | 2163 | if (resizeImage($filepath)) |
@@ -2214,7 +2172,8 @@ function genThumbnail() | |||
2214 | 2172 | ||
2215 | // Otherwise, return an empty image (8x8 transparent gif) | 2173 | // Otherwise, return an empty image (8x8 transparent gif) |
2216 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); | 2174 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); |
2217 | file_put_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname,$blankgif); // Also put something in cache so that this URL is not requested twice. | 2175 | // Also put something in cache so that this URL is not requested twice. |
2176 | file_put_contents($cacheDir .'/'. $blankname, $blankgif); | ||
2218 | header('Content-Type: image/gif'); | 2177 | header('Content-Type: image/gif'); |
2219 | echo $blankgif; | 2178 | echo $blankgif; |
2220 | } | 2179 | } |
@@ -2252,8 +2211,9 @@ function resizeImage($filepath) | |||
2252 | return true; | 2211 | return true; |
2253 | } | 2212 | } |
2254 | 2213 | ||
2255 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. | 2214 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail($conf); exit; } // Thumbnail generation/cache does not need the link database. |
2256 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS(); exit; } | 2215 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS($conf); exit; } |
2257 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; | 2216 | if (!isset($_SESSION['LINKS_PER_PAGE'])) { |
2258 | renderPage(); | 2217 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); |
2259 | ?> | 2218 | } |
2219 | renderPage($conf, $pluginManager); | ||