diff options
author | ArthurHoaro <arthur@hoa.ro> | 2019-07-27 12:34:30 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2019-07-27 12:34:30 +0200 |
commit | 38672ba0d1c722e5d6d33a58255ceb55e9410e46 (patch) | |
tree | dae4c7c47532380eac3ae641db99122fc77c93dc /index.php | |
parent | 83faedadff76c5bdca036f39f13943f63b27e164 (diff) | |
parent | 1e77e0448bbd25675d8c0fe4a73206ad9048904b (diff) | |
download | Shaarli-38672ba0d1c722e5d6d33a58255ceb55e9410e46.tar.gz Shaarli-38672ba0d1c722e5d6d33a58255ceb55e9410e46.tar.zst Shaarli-38672ba0d1c722e5d6d33a58255ceb55e9410e46.zip |
Merge tag 'v0.10.4' into stable
Release v0.10.4
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 1279 |
1 files changed, 441 insertions, 838 deletions
@@ -34,7 +34,7 @@ if (date_default_timezone_get() == '') { | |||
34 | define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0))); | 34 | define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0))); |
35 | 35 | ||
36 | // High execution time in case of problematic imports/exports. | 36 | // High execution time in case of problematic imports/exports. |
37 | ini_set('max_input_time','60'); | 37 | ini_set('max_input_time', '60'); |
38 | 38 | ||
39 | // Try to set max upload file size and read | 39 | // Try to set max upload file size and read |
40 | ini_set('memory_limit', '128M'); | 40 | ini_set('memory_limit', '128M'); |
@@ -54,7 +54,7 @@ if (! file_exists(__DIR__ . '/vendor/autoload.php')) { | |||
54 | ."If you installed Shaarli through Git or using the development branch,\n" | 54 | ."If you installed Shaarli through Git or using the development branch,\n" |
55 | ."please refer to the installation documentation to install PHP" | 55 | ."please refer to the installation documentation to install PHP" |
56 | ." dependencies using Composer:\n" | 56 | ." dependencies using Composer:\n" |
57 | ."- https://shaarli.readthedocs.io/en/master/Server-requirements/\n" | 57 | ."- https://shaarli.readthedocs.io/en/master/Server-configuration/\n" |
58 | ."- https://shaarli.readthedocs.io/en/master/Download-and-Installation/"; | 58 | ."- https://shaarli.readthedocs.io/en/master/Download-and-Installation/"; |
59 | exit; | 59 | exit; |
60 | } | 60 | } |
@@ -81,15 +81,17 @@ require_once 'application/Utils.php'; | |||
81 | require_once 'application/PluginManager.php'; | 81 | require_once 'application/PluginManager.php'; |
82 | require_once 'application/Router.php'; | 82 | require_once 'application/Router.php'; |
83 | require_once 'application/Updater.php'; | 83 | require_once 'application/Updater.php'; |
84 | use \Shaarli\Config\ConfigManager; | ||
84 | use \Shaarli\Languages; | 85 | use \Shaarli\Languages; |
86 | use \Shaarli\Security\LoginManager; | ||
87 | use \Shaarli\Security\SessionManager; | ||
85 | use \Shaarli\ThemeUtils; | 88 | use \Shaarli\ThemeUtils; |
86 | use \Shaarli\Config\ConfigManager; | 89 | use \Shaarli\Thumbnailer; |
87 | use \Shaarli\SessionManager; | ||
88 | 90 | ||
89 | // Ensure the PHP version is supported | 91 | // Ensure the PHP version is supported |
90 | try { | 92 | try { |
91 | ApplicationUtils::checkPHPVersion('5.5', PHP_VERSION); | 93 | ApplicationUtils::checkPHPVersion('5.5', PHP_VERSION); |
92 | } catch(Exception $exc) { | 94 | } catch (Exception $exc) { |
93 | header('Content-Type: text/plain; charset=utf-8'); | 95 | header('Content-Type: text/plain; charset=utf-8'); |
94 | echo $exc->getMessage(); | 96 | echo $exc->getMessage(); |
95 | exit; | 97 | exit; |
@@ -106,8 +108,6 @@ if (dirname($_SERVER['SCRIPT_NAME']) != '/') { | |||
106 | // Set default cookie expiration and path. | 108 | // Set default cookie expiration and path. |
107 | session_set_cookie_params($cookie['lifetime'], $cookiedir, $_SERVER['SERVER_NAME']); | 109 | session_set_cookie_params($cookie['lifetime'], $cookiedir, $_SERVER['SERVER_NAME']); |
108 | // Set session parameters on server side. | 110 | // Set session parameters on server side. |
109 | // If the user does not access any page within this time, his/her session is considered expired. | ||
110 | define('INACTIVITY_TIMEOUT', 3600); // in seconds. | ||
111 | // Use cookies to store session. | 111 | // Use cookies to store session. |
112 | ini_set('session.use_cookies', 1); | 112 | ini_set('session.use_cookies', 1); |
113 | // Force cookies for session (phpsessionID forbidden in URL). | 113 | // Force cookies for session (phpsessionID forbidden in URL). |
@@ -117,7 +117,7 @@ ini_set('session.use_trans_sid', false); | |||
117 | 117 | ||
118 | session_name('shaarli'); | 118 | session_name('shaarli'); |
119 | // Start session if needed (Some server auto-start sessions). | 119 | // Start session if needed (Some server auto-start sessions). |
120 | if (session_id() == '') { | 120 | if (session_status() == PHP_SESSION_NONE) { |
121 | session_start(); | 121 | session_start(); |
122 | } | 122 | } |
123 | 123 | ||
@@ -129,6 +129,9 @@ if (isset($_COOKIE['shaarli']) && !SessionManager::checkId($_COOKIE['shaarli'])) | |||
129 | 129 | ||
130 | $conf = new ConfigManager(); | 130 | $conf = new ConfigManager(); |
131 | $sessionManager = new SessionManager($_SESSION, $conf); | 131 | $sessionManager = new SessionManager($_SESSION, $conf); |
132 | $loginManager = new LoginManager($GLOBALS, $conf, $sessionManager); | ||
133 | $loginManager->generateStaySignedInToken($_SERVER['REMOTE_ADDR']); | ||
134 | $clientIpId = client_ip_id($_SERVER); | ||
132 | 135 | ||
133 | // LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead. | 136 | // LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead. |
134 | if (! defined('LC_MESSAGES')) { | 137 | if (! defined('LC_MESSAGES')) { |
@@ -178,246 +181,63 @@ if (! is_file($conf->getConfigFileExt())) { | |||
178 | } | 181 | } |
179 | 182 | ||
180 | // Display the installation form if no existing config is found | 183 | // Display the installation form if no existing config is found |
181 | install($conf, $sessionManager); | 184 | install($conf, $sessionManager, $loginManager); |
182 | } | 185 | } |
183 | 186 | ||
184 | // a token depending of deployment salt, user password, and the current ip | 187 | $loginManager->checkLoginState($_COOKIE, $clientIpId); |
185 | define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); | ||
186 | 188 | ||
187 | /** | 189 | /** |
188 | * Checking session state (i.e. is the user still logged in) | 190 | * Adapter function to ensure compatibility with third-party templates |
189 | * | 191 | * |
190 | * @param ConfigManager $conf The configuration manager. | 192 | * @see https://github.com/shaarli/Shaarli/pull/1086 |
191 | * | 193 | * |
192 | * @return bool: true if the user is logged in, false otherwise. | 194 | * @return bool true when the user is logged in, false otherwise |
193 | */ | 195 | */ |
194 | function setup_login_state($conf) | ||
195 | { | ||
196 | if ($conf->get('security.open_shaarli')) { | ||
197 | return true; | ||
198 | } | ||
199 | $userIsLoggedIn = false; // By default, we do not consider the user as logged in; | ||
200 | $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met. | ||
201 | if (! $conf->exists('credentials.login')) { | ||
202 | $userIsLoggedIn = false; // Shaarli is not configured yet. | ||
203 | $loginFailure = true; | ||
204 | } | ||
205 | if (isset($_COOKIE['shaarli_staySignedIn']) && | ||
206 | $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && | ||
207 | !$loginFailure) | ||
208 | { | ||
209 | fillSessionInfo($conf); | ||
210 | $userIsLoggedIn = true; | ||
211 | } | ||
212 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. | ||
213 | if (empty($_SESSION['uid']) | ||
214 | || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != allIPs()) | ||
215 | || time() >= $_SESSION['expires_on']) | ||
216 | { | ||
217 | logout(); | ||
218 | $userIsLoggedIn = false; | ||
219 | $loginFailure = true; | ||
220 | } | ||
221 | if (!empty($_SESSION['longlastingsession'])) { | ||
222 | $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked. | ||
223 | } | ||
224 | else { | ||
225 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date. | ||
226 | } | ||
227 | if (!$loginFailure) { | ||
228 | $userIsLoggedIn = true; | ||
229 | } | ||
230 | |||
231 | return $userIsLoggedIn; | ||
232 | } | ||
233 | $userIsLoggedIn = setup_login_state($conf); | ||
234 | |||
235 | // ------------------------------------------------------------------------------------------ | ||
236 | // Session management | ||
237 | |||
238 | // Returns the IP address of the client (Used to prevent session cookie hijacking.) | ||
239 | function allIPs() | ||
240 | { | ||
241 | $ip = $_SERVER['REMOTE_ADDR']; | ||
242 | // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy. | ||
243 | if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; } | ||
244 | if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; } | ||
245 | return $ip; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * Load user session. | ||
250 | * | ||
251 | * @param ConfigManager $conf Configuration Manager instance. | ||
252 | */ | ||
253 | function fillSessionInfo($conf) | ||
254 | { | ||
255 | $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) | ||
256 | $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. | ||
257 | $_SESSION['username']= $conf->get('credentials.login'); | ||
258 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * Check that user/password is correct. | ||
263 | * | ||
264 | * @param string $login Username | ||
265 | * @param string $password User password | ||
266 | * @param ConfigManager $conf Configuration Manager instance. | ||
267 | * | ||
268 | * @return bool: authentication successful or not. | ||
269 | */ | ||
270 | function check_auth($login, $password, $conf) | ||
271 | { | ||
272 | $hash = sha1($password . $login . $conf->get('credentials.salt')); | ||
273 | if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) | ||
274 | { // Login/password is correct. | ||
275 | fillSessionInfo($conf); | ||
276 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful'); | ||
277 | return true; | ||
278 | } | ||
279 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login failed for user '.$login); | ||
280 | return false; | ||
281 | } | ||
282 | |||
283 | // Returns true if the user is logged in. | ||
284 | function isLoggedIn() | 196 | function isLoggedIn() |
285 | { | 197 | { |
286 | global $userIsLoggedIn; | 198 | global $loginManager; |
287 | return $userIsLoggedIn; | 199 | return $loginManager->isLoggedIn(); |
288 | } | ||
289 | |||
290 | // Force logout. | ||
291 | function logout() { | ||
292 | if (isset($_SESSION)) { | ||
293 | unset($_SESSION['uid']); | ||
294 | unset($_SESSION['ip']); | ||
295 | unset($_SESSION['username']); | ||
296 | unset($_SESSION['privateonly']); | ||
297 | unset($_SESSION['untaggedonly']); | ||
298 | } | ||
299 | setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH); | ||
300 | } | 200 | } |
301 | 201 | ||
302 | 202 | ||
303 | // ------------------------------------------------------------------------------------------ | 203 | // ------------------------------------------------------------------------------------------ |
304 | // Brute force protection system | ||
305 | // Several consecutive failed logins will ban the IP address for 30 minutes. | ||
306 | if (!is_file($conf->get('resource.ban_file', 'data/ipbans.php'))) { | ||
307 | // FIXME! globals | ||
308 | file_put_contents( | ||
309 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
310 | "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>" | ||
311 | ); | ||
312 | } | ||
313 | include $conf->get('resource.ban_file', 'data/ipbans.php'); | ||
314 | /** | ||
315 | * Signal a failed login. Will ban the IP if too many failures: | ||
316 | * | ||
317 | * @param ConfigManager $conf Configuration Manager instance. | ||
318 | */ | ||
319 | function ban_loginFailed($conf) | ||
320 | { | ||
321 | $ip = $_SERVER['REMOTE_ADDR']; | ||
322 | $trusted = $conf->get('security.trusted_proxies', array()); | ||
323 | if (in_array($ip, $trusted)) { | ||
324 | $ip = getIpAddressFromProxy($_SERVER, $trusted); | ||
325 | if (!$ip) { | ||
326 | return; | ||
327 | } | ||
328 | } | ||
329 | $gb = $GLOBALS['IPBANS']; | ||
330 | if (! isset($gb['FAILURES'][$ip])) { | ||
331 | $gb['FAILURES'][$ip]=0; | ||
332 | } | ||
333 | $gb['FAILURES'][$ip]++; | ||
334 | if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1)) | ||
335 | { | ||
336 | $gb['BANS'][$ip] = time() + $conf->get('security.ban_after', 1800); | ||
337 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'IP address banned from login'); | ||
338 | } | ||
339 | $GLOBALS['IPBANS'] = $gb; | ||
340 | file_put_contents( | ||
341 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
342 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
343 | ); | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * Signals a successful login. Resets failed login counter. | ||
348 | * | ||
349 | * @param ConfigManager $conf Configuration Manager instance. | ||
350 | */ | ||
351 | function ban_loginOk($conf) | ||
352 | { | ||
353 | $ip = $_SERVER['REMOTE_ADDR']; | ||
354 | $gb = $GLOBALS['IPBANS']; | ||
355 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | ||
356 | $GLOBALS['IPBANS'] = $gb; | ||
357 | file_put_contents( | ||
358 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
359 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
360 | ); | ||
361 | } | ||
362 | |||
363 | /** | ||
364 | * Checks if the user CAN login. If 'true', the user can try to login. | ||
365 | * | ||
366 | * @param ConfigManager $conf Configuration Manager instance. | ||
367 | * | ||
368 | * @return bool: true if the user is allowed to login. | ||
369 | */ | ||
370 | function ban_canLogin($conf) | ||
371 | { | ||
372 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | ||
373 | if (isset($gb['BANS'][$ip])) | ||
374 | { | ||
375 | // User is banned. Check if the ban has expired: | ||
376 | if ($gb['BANS'][$ip]<=time()) | ||
377 | { // Ban expired, user can try to login again. | ||
378 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Ban lifted.'); | ||
379 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | ||
380 | file_put_contents( | ||
381 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
382 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
383 | ); | ||
384 | return true; // Ban has expired, user can login. | ||
385 | } | ||
386 | return false; // User is banned. | ||
387 | } | ||
388 | return true; // User is not banned. | ||
389 | } | ||
390 | |||
391 | // ------------------------------------------------------------------------------------------ | ||
392 | // Process login form: Check if login/password is correct. | 204 | // Process login form: Check if login/password is correct. |
393 | if (isset($_POST['login'])) | 205 | if (isset($_POST['login'])) { |
394 | { | 206 | if (! $loginManager->canLogin($_SERVER)) { |
395 | if (!ban_canLogin($conf)) die(t('I said: NO. You are banned for the moment. Go away.')); | 207 | die(t('I said: NO. You are banned for the moment. Go away.')); |
208 | } | ||
396 | if (isset($_POST['password']) | 209 | if (isset($_POST['password']) |
397 | && $sessionManager->checkToken($_POST['token']) | 210 | && $sessionManager->checkToken($_POST['token']) |
398 | && (check_auth($_POST['login'], $_POST['password'], $conf)) | 211 | && $loginManager->checkCredentials($_SERVER['REMOTE_ADDR'], $clientIpId, $_POST['login'], $_POST['password']) |
399 | ) { // Login/password is OK. | 212 | ) { |
400 | ban_loginOk($conf); | 213 | $loginManager->handleSuccessfulLogin($_SERVER); |
401 | // If user wants to keep the session cookie even after the browser closes: | 214 | |
402 | if (!empty($_POST['longlastingsession'])) | 215 | $cookiedir = ''; |
403 | { | 216 | if (dirname($_SERVER['SCRIPT_NAME']) != '/') { |
404 | $_SESSION['longlastingsession'] = 31536000; // (31536000 seconds = 1 year) | ||
405 | $expiration = time() + $_SESSION['longlastingsession']; // calculate relative cookie expiration (1 year from now) | ||
406 | setcookie('shaarli_staySignedIn', STAY_SIGNED_IN_TOKEN, $expiration, WEB_PATH); | ||
407 | $_SESSION['expires_on'] = $expiration; // Set session expiration on server-side. | ||
408 | |||
409 | $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; | ||
410 | session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['SERVER_NAME']); // Set session cookie expiration on client side | ||
411 | // Note: Never forget the trailing slash on the cookie path! | 217 | // Note: Never forget the trailing slash on the cookie path! |
412 | session_regenerate_id(true); // Send cookie with new expiration date to browser. | 218 | $cookiedir = dirname($_SERVER["SCRIPT_NAME"]) . '/'; |
413 | } | 219 | } |
414 | else // Standard session expiration (=when browser closes) | 220 | |
415 | { | 221 | if (!empty($_POST['longlastingsession'])) { |
416 | $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; | 222 | // Keep the session cookie even after the browser closes |
417 | session_set_cookie_params(0,$cookiedir,$_SERVER['SERVER_NAME']); // 0 means "When browser closes" | 223 | $sessionManager->setStaySignedIn(true); |
418 | session_regenerate_id(true); | 224 | $expirationTime = $sessionManager->extendSession(); |
225 | |||
226 | setcookie( | ||
227 | $loginManager::$STAY_SIGNED_IN_COOKIE, | ||
228 | $loginManager->getStaySignedInToken(), | ||
229 | $expirationTime, | ||
230 | WEB_PATH | ||
231 | ); | ||
232 | } else { | ||
233 | // Standard session expiration (=when browser closes) | ||
234 | $expirationTime = 0; | ||
419 | } | 235 | } |
420 | 236 | ||
237 | // Send cookie with the new expiration date to the browser | ||
238 | session_set_cookie_params($expirationTime, $cookiedir, $_SERVER['SERVER_NAME']); | ||
239 | session_regenerate_id(true); | ||
240 | |||
421 | // Optional redirect after login: | 241 | // Optional redirect after login: |
422 | if (isset($_GET['post'])) { | 242 | if (isset($_GET['post'])) { |
423 | $uri = '?post='. urlencode($_GET['post']); | 243 | $uri = '?post='. urlencode($_GET['post']); |
@@ -442,11 +262,10 @@ if (isset($_POST['login'])) | |||
442 | exit; | 262 | exit; |
443 | } | 263 | } |
444 | } | 264 | } |
445 | header('Location: ?'); exit; | 265 | header('Location: ?'); |
446 | } | 266 | exit; |
447 | else | 267 | } else { |
448 | { | 268 | $loginManager->handleFailedLogin($_SERVER); |
449 | ban_loginFailed($conf); | ||
450 | $redir = '&username='. urlencode($_POST['login']); | 269 | $redir = '&username='. urlencode($_POST['login']); |
451 | if (isset($_GET['post'])) { | 270 | if (isset($_GET['post'])) { |
452 | $redir .= '&post=' . urlencode($_GET['post']); | 271 | $redir .= '&post=' . urlencode($_GET['post']); |
@@ -465,22 +284,26 @@ if (isset($_POST['login'])) | |||
465 | // ------------------------------------------------------------------------------------------ | 284 | // ------------------------------------------------------------------------------------------ |
466 | // Token management for XSRF protection | 285 | // Token management for XSRF protection |
467 | // Token should be used in any form which acts on data (create,update,delete,import...). | 286 | // Token should be used in any form which acts on data (create,update,delete,import...). |
468 | if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. | 287 | if (!isset($_SESSION['tokens'])) { |
288 | $_SESSION['tokens']=array(); // Token are attached to the session. | ||
289 | } | ||
469 | 290 | ||
470 | /** | 291 | /** |
471 | * Daily RSS feed: 1 RSS entry per day giving all the links on that day. | 292 | * Daily RSS feed: 1 RSS entry per day giving all the links on that day. |
472 | * Gives the last 7 days (which have links). | 293 | * Gives the last 7 days (which have links). |
473 | * This RSS feed cannot be filtered. | 294 | * This RSS feed cannot be filtered. |
474 | * | 295 | * |
475 | * @param ConfigManager $conf Configuration Manager instance. | 296 | * @param ConfigManager $conf Configuration Manager instance |
297 | * @param LoginManager $loginManager LoginManager instance | ||
476 | */ | 298 | */ |
477 | function showDailyRSS($conf) { | 299 | function showDailyRSS($conf, $loginManager) |
300 | { | ||
478 | // Cache system | 301 | // Cache system |
479 | $query = $_SERVER['QUERY_STRING']; | 302 | $query = $_SERVER['QUERY_STRING']; |
480 | $cache = new CachedPage( | 303 | $cache = new CachedPage( |
481 | $conf->get('config.PAGE_CACHE'), | 304 | $conf->get('config.PAGE_CACHE'), |
482 | page_url($_SERVER), | 305 | page_url($_SERVER), |
483 | startsWith($query,'do=dailyrss') && !isLoggedIn() | 306 | startsWith($query, 'do=dailyrss') && !$loginManager->isLoggedIn() |
484 | ); | 307 | ); |
485 | $cached = $cache->cachedVersion(); | 308 | $cached = $cache->cachedVersion(); |
486 | if (!empty($cached)) { | 309 | if (!empty($cached)) { |
@@ -492,7 +315,7 @@ function showDailyRSS($conf) { | |||
492 | // Read links from database (and filter private links if used it not logged in). | 315 | // Read links from database (and filter private links if used it not logged in). |
493 | $LINKSDB = new LinkDB( | 316 | $LINKSDB = new LinkDB( |
494 | $conf->get('resource.datastore'), | 317 | $conf->get('resource.datastore'), |
495 | isLoggedIn(), | 318 | $loginManager->isLoggedIn(), |
496 | $conf->get('privacy.hide_public_links'), | 319 | $conf->get('privacy.hide_public_links'), |
497 | $conf->get('redirector.url'), | 320 | $conf->get('redirector.url'), |
498 | $conf->get('redirector.encode_url') | 321 | $conf->get('redirector.encode_url') |
@@ -542,7 +365,6 @@ function showDailyRSS($conf) { | |||
542 | $conf->get('redirector.url'), | 365 | $conf->get('redirector.url'), |
543 | $conf->get('redirector.encode_url') | 366 | $conf->get('redirector.encode_url') |
544 | ); | 367 | ); |
545 | $link['thumbnail'] = thumbnail($conf, $link['url']); | ||
546 | $link['timestamp'] = $link['created']->getTimestamp(); | 368 | $link['timestamp'] = $link['created']->getTimestamp(); |
547 | if (startsWith($link['url'], '?')) { | 369 | if (startsWith($link['url'], '?')) { |
548 | $link['url'] = index_url($_SERVER) . $link['url']; // make permalink URL absolute | 370 | $link['url'] = index_url($_SERVER) . $link['url']; // make permalink URL absolute |
@@ -557,6 +379,7 @@ function showDailyRSS($conf) { | |||
557 | $tpl->assign('links', $links); | 379 | $tpl->assign('links', $links); |
558 | $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS))); | 380 | $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS))); |
559 | $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false)); | 381 | $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false)); |
382 | $tpl->assign('index_url', $pageaddr); | ||
560 | $html = $tpl->draw('dailyrss', true); | 383 | $html = $tpl->draw('dailyrss', true); |
561 | 384 | ||
562 | echo $html . PHP_EOL; | 385 | echo $html . PHP_EOL; |
@@ -574,13 +397,14 @@ function showDailyRSS($conf) { | |||
574 | * @param PageBuilder $pageBuilder Template engine wrapper. | 397 | * @param PageBuilder $pageBuilder Template engine wrapper. |
575 | * @param LinkDB $LINKSDB LinkDB instance. | 398 | * @param LinkDB $LINKSDB LinkDB instance. |
576 | * @param ConfigManager $conf Configuration Manager instance. | 399 | * @param ConfigManager $conf Configuration Manager instance. |
577 | * @param PluginManager $pluginManager Plugin Manager instane. | 400 | * @param PluginManager $pluginManager Plugin Manager instance. |
401 | * @param LoginManager $loginManager Login Manager instance | ||
578 | */ | 402 | */ |
579 | function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | 403 | function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager) |
580 | { | 404 | { |
581 | $day = date('Ymd', strtotime('-1 day')); // Yesterday, in format YYYYMMDD. | 405 | $day = date('Ymd', strtotime('-1 day')); // Yesterday, in format YYYYMMDD. |
582 | if (isset($_GET['day'])) { | 406 | if (isset($_GET['day'])) { |
583 | $day = $_GET['day']; | 407 | $day = $_GET['day']; |
584 | } | 408 | } |
585 | 409 | ||
586 | $days = $LINKSDB->days(); | 410 | $days = $LINKSDB->days(); |
@@ -598,7 +422,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | |||
598 | $previousday=$days[$i - 1]; | 422 | $previousday=$days[$i - 1]; |
599 | } | 423 | } |
600 | if ($i < count($days) - 1) { | 424 | if ($i < count($days) - 1) { |
601 | $nextday = $days[$i + 1]; | 425 | $nextday = $days[$i + 1]; |
602 | } | 426 | } |
603 | } | 427 | } |
604 | try { | 428 | try { |
@@ -609,8 +433,8 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | |||
609 | } | 433 | } |
610 | 434 | ||
611 | // We pre-format some fields for proper output. | 435 | // We pre-format some fields for proper output. |
612 | foreach($linksToDisplay as $key => $link) { | 436 | foreach ($linksToDisplay as $key => $link) { |
613 | $taglist = explode(' ',$link['tags']); | 437 | $taglist = explode(' ', $link['tags']); |
614 | uasort($taglist, 'strcasecmp'); | 438 | uasort($taglist, 'strcasecmp'); |
615 | $linksToDisplay[$key]['taglist']=$taglist; | 439 | $linksToDisplay[$key]['taglist']=$taglist; |
616 | $linksToDisplay[$key]['formatedDescription'] = format_description( | 440 | $linksToDisplay[$key]['formatedDescription'] = format_description( |
@@ -618,10 +442,23 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | |||
618 | $conf->get('redirector.url'), | 442 | $conf->get('redirector.url'), |
619 | $conf->get('redirector.encode_url') | 443 | $conf->get('redirector.encode_url') |
620 | ); | 444 | ); |
621 | $linksToDisplay[$key]['thumbnail'] = thumbnail($conf, $link['url']); | ||
622 | $linksToDisplay[$key]['timestamp'] = $link['created']->getTimestamp(); | 445 | $linksToDisplay[$key]['timestamp'] = $link['created']->getTimestamp(); |
623 | } | 446 | } |
624 | 447 | ||
448 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); | ||
449 | $data = array( | ||
450 | 'pagetitle' => $conf->get('general.title') .' - '. format_date($dayDate, false), | ||
451 | 'linksToDisplay' => $linksToDisplay, | ||
452 | 'day' => $dayDate->getTimestamp(), | ||
453 | 'dayDate' => $dayDate, | ||
454 | 'previousday' => $previousday, | ||
455 | 'nextday' => $nextday, | ||
456 | ); | ||
457 | |||
458 | /* Hook is called before column construction so that plugins don't have | ||
459 | to deal with columns. */ | ||
460 | $pluginManager->executeHooks('render_daily', $data, array('loggedin' => $loginManager->isLoggedIn())); | ||
461 | |||
625 | /* We need to spread the articles on 3 columns. | 462 | /* We need to spread the articles on 3 columns. |
626 | I did not want to use a JavaScript lib like http://masonry.desandro.com/ | 463 | I did not want to use a JavaScript lib like http://masonry.desandro.com/ |
627 | so I manually spread entries with a simple method: I roughly evaluate the | 464 | so I manually spread entries with a simple method: I roughly evaluate the |
@@ -629,14 +466,14 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | |||
629 | */ | 466 | */ |
630 | $columns = array(array(), array(), array()); // Entries to display, for each column. | 467 | $columns = array(array(), array(), array()); // Entries to display, for each column. |
631 | $fill = array(0, 0, 0); // Rough estimate of columns fill. | 468 | $fill = array(0, 0, 0); // Rough estimate of columns fill. |
632 | foreach($linksToDisplay as $key => $link) { | 469 | foreach ($data['linksToDisplay'] as $key => $link) { |
633 | // Roughly estimate length of entry (by counting characters) | 470 | // Roughly estimate length of entry (by counting characters) |
634 | // Title: 30 chars = 1 line. 1 line is 30 pixels height. | 471 | // Title: 30 chars = 1 line. 1 line is 30 pixels height. |
635 | // Description: 836 characters gives roughly 342 pixel height. | 472 | // Description: 836 characters gives roughly 342 pixel height. |
636 | // This is not perfect, but it's usually OK. | 473 | // This is not perfect, but it's usually OK. |
637 | $length = strlen($link['title']) + (342 * strlen($link['description'])) / 836; | 474 | $length = strlen($link['title']) + (342 * strlen($link['description'])) / 836; |
638 | if ($link['thumbnail']) { | 475 | if ($link['thumbnail']) { |
639 | $length += 100; // 1 thumbnails roughly takes 100 pixels height. | 476 | $length += 100; // 1 thumbnails roughly takes 100 pixels height. |
640 | } | 477 | } |
641 | // Then put in column which is the less filled: | 478 | // Then put in column which is the less filled: |
642 | $smallest = min($fill); // find smallest value in array. | 479 | $smallest = min($fill); // find smallest value in array. |
@@ -645,23 +482,13 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | |||
645 | $fill[$index] += $length; | 482 | $fill[$index] += $length; |
646 | } | 483 | } |
647 | 484 | ||
648 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); | 485 | $data['cols'] = $columns; |
649 | $data = array( | ||
650 | 'pagetitle' => $conf->get('general.title') .' - '. format_date($dayDate, false), | ||
651 | 'linksToDisplay' => $linksToDisplay, | ||
652 | 'cols' => $columns, | ||
653 | 'day' => $dayDate->getTimestamp(), | ||
654 | 'dayDate' => $dayDate, | ||
655 | 'previousday' => $previousday, | ||
656 | 'nextday' => $nextday, | ||
657 | ); | ||
658 | |||
659 | $pluginManager->executeHooks('render_daily', $data, array('loggedin' => isLoggedIn())); | ||
660 | 486 | ||
661 | foreach ($data as $key => $value) { | 487 | foreach ($data as $key => $value) { |
662 | $pageBuilder->assign($key, $value); | 488 | $pageBuilder->assign($key, $value); |
663 | } | 489 | } |
664 | 490 | ||
491 | $pageBuilder->assign('pagetitle', t('Daily') .' - '. $conf->get('general.title', 'Shaarli')); | ||
665 | $pageBuilder->renderPage('daily'); | 492 | $pageBuilder->renderPage('daily'); |
666 | exit; | 493 | exit; |
667 | } | 494 | } |
@@ -674,8 +501,9 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | |||
674 | * @param ConfigManager $conf Configuration Manager instance. | 501 | * @param ConfigManager $conf Configuration Manager instance. |
675 | * @param PluginManager $pluginManager Plugin Manager instance. | 502 | * @param PluginManager $pluginManager Plugin Manager instance. |
676 | */ | 503 | */ |
677 | function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { | 504 | function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) |
678 | buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager); // Compute list of links to display | 505 | { |
506 | buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); | ||
679 | $PAGE->renderPage('linklist'); | 507 | $PAGE->renderPage('linklist'); |
680 | } | 508 | } |
681 | 509 | ||
@@ -687,14 +515,16 @@ function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { | |||
687 | * @param LinkDB $LINKSDB | 515 | * @param LinkDB $LINKSDB |
688 | * @param History $history instance | 516 | * @param History $history instance |
689 | * @param SessionManager $sessionManager SessionManager instance | 517 | * @param SessionManager $sessionManager SessionManager instance |
518 | * @param LoginManager $loginManager LoginManager instance | ||
690 | */ | 519 | */ |
691 | function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | 520 | function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $loginManager) |
692 | { | 521 | { |
693 | $updater = new Updater( | 522 | $updater = new Updater( |
694 | read_updates_file($conf->get('resource.updates')), | 523 | read_updates_file($conf->get('resource.updates')), |
695 | $LINKSDB, | 524 | $LINKSDB, |
696 | $conf, | 525 | $conf, |
697 | isLoggedIn() | 526 | $loginManager->isLoggedIn(), |
527 | $_SESSION | ||
698 | ); | 528 | ); |
699 | try { | 529 | try { |
700 | $newUpdates = $updater->update(); | 530 | $newUpdates = $updater->update(); |
@@ -704,23 +534,21 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
704 | $updater->getDoneUpdates() | 534 | $updater->getDoneUpdates() |
705 | ); | 535 | ); |
706 | } | 536 | } |
707 | } | 537 | } catch (Exception $e) { |
708 | catch(Exception $e) { | ||
709 | die($e->getMessage()); | 538 | die($e->getMessage()); |
710 | } | 539 | } |
711 | 540 | ||
712 | $PAGE = new PageBuilder($conf, $LINKSDB, $sessionManager->generateToken()); | 541 | $PAGE = new PageBuilder($conf, $_SESSION, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn()); |
713 | $PAGE->assign('linkcount', count($LINKSDB)); | 542 | $PAGE->assign('linkcount', count($LINKSDB)); |
714 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); | 543 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); |
715 | $PAGE->assign('plugin_errors', $pluginManager->getErrors()); | 544 | $PAGE->assign('plugin_errors', $pluginManager->getErrors()); |
716 | 545 | ||
717 | // Determine which page will be rendered. | 546 | // Determine which page will be rendered. |
718 | $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; | 547 | $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; |
719 | $targetPage = Router::findPage($query, $_GET, isLoggedIn()); | 548 | $targetPage = Router::findPage($query, $_GET, $loginManager->isLoggedIn()); |
720 | 549 | ||
721 | if ( | 550 | if (// if the user isn't logged in |
722 | // if the user isn't logged in | 551 | !$loginManager->isLoggedIn() && |
723 | !isLoggedIn() && | ||
724 | // and Shaarli doesn't have public content... | 552 | // and Shaarli doesn't have public content... |
725 | $conf->get('privacy.hide_public_links') && | 553 | $conf->get('privacy.hide_public_links') && |
726 | // and is configured to enforce the login | 554 | // and is configured to enforce the login |
@@ -743,75 +571,83 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
743 | 'footer', | 571 | 'footer', |
744 | ); | 572 | ); |
745 | 573 | ||
746 | foreach($common_hooks as $name) { | 574 | foreach ($common_hooks as $name) { |
747 | $plugin_data = array(); | 575 | $plugin_data = array(); |
748 | $pluginManager->executeHooks('render_' . $name, $plugin_data, | 576 | $pluginManager->executeHooks( |
577 | 'render_' . $name, | ||
578 | $plugin_data, | ||
749 | array( | 579 | array( |
750 | 'target' => $targetPage, | 580 | 'target' => $targetPage, |
751 | 'loggedin' => isLoggedIn() | 581 | 'loggedin' => $loginManager->isLoggedIn() |
752 | ) | 582 | ) |
753 | ); | 583 | ); |
754 | $PAGE->assign('plugins_' . $name, $plugin_data); | 584 | $PAGE->assign('plugins_' . $name, $plugin_data); |
755 | } | 585 | } |
756 | 586 | ||
757 | // -------- Display login form. | 587 | // -------- Display login form. |
758 | if ($targetPage == Router::$PAGE_LOGIN) | 588 | if ($targetPage == Router::$PAGE_LOGIN) { |
759 | { | 589 | if ($conf->get('security.open_shaarli')) { |
760 | if ($conf->get('security.open_shaarli')) { header('Location: ?'); exit; } // No need to login for open Shaarli | 590 | header('Location: ?'); |
591 | exit; | ||
592 | } // No need to login for open Shaarli | ||
761 | if (isset($_GET['username'])) { | 593 | if (isset($_GET['username'])) { |
762 | $PAGE->assign('username', escape($_GET['username'])); | 594 | $PAGE->assign('username', escape($_GET['username'])); |
763 | } | 595 | } |
764 | $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):'')); | 596 | $PAGE->assign('returnurl', (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):'')); |
765 | // add default state of the 'remember me' checkbox | 597 | // add default state of the 'remember me' checkbox |
766 | $PAGE->assign('remember_user_default', $conf->get('privacy.remember_user_default')); | 598 | $PAGE->assign('remember_user_default', $conf->get('privacy.remember_user_default')); |
599 | $PAGE->assign('user_can_login', $loginManager->canLogin($_SERVER)); | ||
600 | $PAGE->assign('pagetitle', t('Login') .' - '. $conf->get('general.title', 'Shaarli')); | ||
767 | $PAGE->renderPage('loginform'); | 601 | $PAGE->renderPage('loginform'); |
768 | exit; | 602 | exit; |
769 | } | 603 | } |
770 | // -------- User wants to logout. | 604 | // -------- User wants to logout. |
771 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) | 605 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) { |
772 | { | ||
773 | invalidateCaches($conf->get('resource.page_cache')); | 606 | invalidateCaches($conf->get('resource.page_cache')); |
774 | logout(); | 607 | $sessionManager->logout(); |
608 | setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, 'false', 0, WEB_PATH); | ||
775 | header('Location: ?'); | 609 | header('Location: ?'); |
776 | exit; | 610 | exit; |
777 | } | 611 | } |
778 | 612 | ||
779 | // -------- Picture wall | 613 | // -------- Picture wall |
780 | if ($targetPage == Router::$PAGE_PICWALL) | 614 | if ($targetPage == Router::$PAGE_PICWALL) { |
781 | { | 615 | $PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli')); |
616 | if (! $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) { | ||
617 | $PAGE->assign('linksToDisplay', []); | ||
618 | $PAGE->renderPage('picwall'); | ||
619 | exit; | ||
620 | } | ||
621 | |||
782 | // Optionally filter the results: | 622 | // Optionally filter the results: |
783 | $links = $LINKSDB->filterSearch($_GET); | 623 | $links = $LINKSDB->filterSearch($_GET); |
784 | $linksToDisplay = array(); | 624 | $linksToDisplay = array(); |
785 | 625 | ||
786 | // Get only links which have a thumbnail. | 626 | // Get only links which have a thumbnail. |
787 | foreach($links as $link) | 627 | // Note: we do not retrieve thumbnails here, the request is too heavy. |
788 | { | 628 | foreach ($links as $key => $link) { |
789 | $permalink='?'.$link['shorturl']; | 629 | if (isset($link['thumbnail']) && $link['thumbnail'] !== false) { |
790 | $thumb=lazyThumbnail($conf, $link['url'],$permalink); | 630 | $linksToDisplay[] = $link; // Add to array. |
791 | if ($thumb!='') // Only output links which have a thumbnail. | ||
792 | { | ||
793 | $link['thumbnail']=$thumb; // Thumbnail HTML code. | ||
794 | $linksToDisplay[]=$link; // Add to array. | ||
795 | } | 631 | } |
796 | } | 632 | } |
797 | 633 | ||
798 | $data = array( | 634 | $data = array( |
799 | 'linksToDisplay' => $linksToDisplay, | 635 | 'linksToDisplay' => $linksToDisplay, |
800 | ); | 636 | ); |
801 | $pluginManager->executeHooks('render_picwall', $data, array('loggedin' => isLoggedIn())); | 637 | $pluginManager->executeHooks('render_picwall', $data, array('loggedin' => $loginManager->isLoggedIn())); |
802 | 638 | ||
803 | foreach ($data as $key => $value) { | 639 | foreach ($data as $key => $value) { |
804 | $PAGE->assign($key, $value); | 640 | $PAGE->assign($key, $value); |
805 | } | 641 | } |
806 | 642 | ||
643 | |||
807 | $PAGE->renderPage('picwall'); | 644 | $PAGE->renderPage('picwall'); |
808 | exit; | 645 | exit; |
809 | } | 646 | } |
810 | 647 | ||
811 | // -------- Tag cloud | 648 | // -------- Tag cloud |
812 | if ($targetPage == Router::$PAGE_TAGCLOUD) | 649 | if ($targetPage == Router::$PAGE_TAGCLOUD) { |
813 | { | 650 | $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : ''; |
814 | $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; | ||
815 | $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; | 651 | $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; |
816 | $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); | 652 | $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); |
817 | 653 | ||
@@ -825,7 +661,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
825 | alphabetical_sort($tags, false, true); | 661 | alphabetical_sort($tags, false, true); |
826 | 662 | ||
827 | $tagList = array(); | 663 | $tagList = array(); |
828 | foreach($tags as $key => $value) { | 664 | foreach ($tags as $key => $value) { |
829 | if (in_array($key, $filteringTags)) { | 665 | if (in_array($key, $filteringTags)) { |
830 | continue; | 666 | continue; |
831 | } | 667 | } |
@@ -839,24 +675,26 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
839 | ); | 675 | ); |
840 | } | 676 | } |
841 | 677 | ||
678 | $searchTags = implode(' ', escape($filteringTags)); | ||
842 | $data = array( | 679 | $data = array( |
843 | 'search_tags' => implode(' ', escape($filteringTags)), | 680 | 'search_tags' => $searchTags, |
844 | 'tags' => $tagList, | 681 | 'tags' => $tagList, |
845 | ); | 682 | ); |
846 | $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); | 683 | $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => $loginManager->isLoggedIn())); |
847 | 684 | ||
848 | foreach ($data as $key => $value) { | 685 | foreach ($data as $key => $value) { |
849 | $PAGE->assign($key, $value); | 686 | $PAGE->assign($key, $value); |
850 | } | 687 | } |
851 | 688 | ||
689 | $searchTags = ! empty($searchTags) ? $searchTags .' - ' : ''; | ||
690 | $PAGE->assign('pagetitle', $searchTags. t('Tag cloud') .' - '. $conf->get('general.title', 'Shaarli')); | ||
852 | $PAGE->renderPage('tag.cloud'); | 691 | $PAGE->renderPage('tag.cloud'); |
853 | exit; | 692 | exit; |
854 | } | 693 | } |
855 | 694 | ||
856 | // -------- Tag list | 695 | // -------- Tag list |
857 | if ($targetPage == Router::$PAGE_TAGLIST) | 696 | if ($targetPage == Router::$PAGE_TAGLIST) { |
858 | { | 697 | $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : ''; |
859 | $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; | ||
860 | $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; | 698 | $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; |
861 | $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); | 699 | $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); |
862 | foreach ($filteringTags as $tag) { | 700 | foreach ($filteringTags as $tag) { |
@@ -869,23 +707,26 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
869 | alphabetical_sort($tags, false, true); | 707 | alphabetical_sort($tags, false, true); |
870 | } | 708 | } |
871 | 709 | ||
710 | $searchTags = implode(' ', escape($filteringTags)); | ||
872 | $data = [ | 711 | $data = [ |
873 | 'search_tags' => implode(' ', escape($filteringTags)), | 712 | 'search_tags' => $searchTags, |
874 | 'tags' => $tags, | 713 | 'tags' => $tags, |
875 | ]; | 714 | ]; |
876 | $pluginManager->executeHooks('render_taglist', $data, ['loggedin' => isLoggedIn()]); | 715 | $pluginManager->executeHooks('render_taglist', $data, ['loggedin' => $loginManager->isLoggedIn()]); |
877 | 716 | ||
878 | foreach ($data as $key => $value) { | 717 | foreach ($data as $key => $value) { |
879 | $PAGE->assign($key, $value); | 718 | $PAGE->assign($key, $value); |
880 | } | 719 | } |
881 | 720 | ||
721 | $searchTags = ! empty($searchTags) ? $searchTags .' - ' : ''; | ||
722 | $PAGE->assign('pagetitle', $searchTags . t('Tag list') .' - '. $conf->get('general.title', 'Shaarli')); | ||
882 | $PAGE->renderPage('tag.list'); | 723 | $PAGE->renderPage('tag.list'); |
883 | exit; | 724 | exit; |
884 | } | 725 | } |
885 | 726 | ||
886 | // Daily page. | 727 | // Daily page. |
887 | if ($targetPage == Router::$PAGE_DAILY) { | 728 | if ($targetPage == Router::$PAGE_DAILY) { |
888 | showDaily($PAGE, $LINKSDB, $conf, $pluginManager); | 729 | showDaily($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); |
889 | } | 730 | } |
890 | 731 | ||
891 | // ATOM and RSS feed. | 732 | // ATOM and RSS feed. |
@@ -898,7 +739,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
898 | $cache = new CachedPage( | 739 | $cache = new CachedPage( |
899 | $conf->get('resource.page_cache'), | 740 | $conf->get('resource.page_cache'), |
900 | page_url($_SERVER), | 741 | page_url($_SERVER), |
901 | startsWith($query,'do='. $targetPage) && !isLoggedIn() | 742 | startsWith($query, 'do='. $targetPage) && !$loginManager->isLoggedIn() |
902 | ); | 743 | ); |
903 | $cached = $cache->cachedVersion(); | 744 | $cached = $cache->cachedVersion(); |
904 | if (!empty($cached)) { | 745 | if (!empty($cached)) { |
@@ -907,15 +748,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
907 | } | 748 | } |
908 | 749 | ||
909 | // Generate data. | 750 | // Generate data. |
910 | $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); | 751 | $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, $loginManager->isLoggedIn()); |
911 | $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); | 752 | $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); |
912 | $feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !isLoggedIn()); | 753 | $feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !$loginManager->isLoggedIn()); |
913 | $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$conf->get('feed.rss_permalinks')); | 754 | $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$conf->get('feed.rss_permalinks')); |
914 | $data = $feedGenerator->buildData(); | 755 | $data = $feedGenerator->buildData(); |
915 | 756 | ||
916 | // Process plugin hook. | 757 | // Process plugin hook. |
917 | $pluginManager->executeHooks('render_feed', $data, array( | 758 | $pluginManager->executeHooks('render_feed', $data, array( |
918 | 'loggedin' => isLoggedIn(), | 759 | 'loggedin' => $loginManager->isLoggedIn(), |
919 | 'target' => $targetPage, | 760 | 'target' => $targetPage, |
920 | )); | 761 | )); |
921 | 762 | ||
@@ -936,11 +777,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
936 | } | 777 | } |
937 | 778 | ||
938 | // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) | 779 | // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) |
939 | if (isset($_GET['addtag'])) | 780 | if (isset($_GET['addtag'])) { |
940 | { | ||
941 | // Get previous URL (http_referer) and add the tag to the searchtags parameters in query. | 781 | // Get previous URL (http_referer) and add the tag to the searchtags parameters in query. |
942 | if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER | 782 | if (empty($_SERVER['HTTP_REFERER'])) { |
943 | parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); | 783 | // In case browser does not send HTTP_REFERER |
784 | header('Location: ?searchtags='.urlencode($_GET['addtag'])); | ||
785 | exit; | ||
786 | } | ||
787 | parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); | ||
944 | 788 | ||
945 | // Prevent redirection loop | 789 | // Prevent redirection loop |
946 | if (isset($params['addtag'])) { | 790 | if (isset($params['addtag'])) { |
@@ -964,12 +808,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
964 | // Append the tag if necessary | 808 | // Append the tag if necessary |
965 | if (empty($params['searchtags'])) { | 809 | if (empty($params['searchtags'])) { |
966 | $params['searchtags'] = trim($_GET['addtag']); | 810 | $params['searchtags'] = trim($_GET['addtag']); |
967 | } | 811 | } elseif ($addtag) { |
968 | else if ($addtag) { | ||
969 | $params['searchtags'] = trim($params['searchtags']).' '.trim($_GET['addtag']); | 812 | $params['searchtags'] = trim($params['searchtags']).' '.trim($_GET['addtag']); |
970 | } | 813 | } |
971 | 814 | ||
972 | unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) | 815 | // We also remove page (keeping the same page has no sense, since the |
816 | // results are different) | ||
817 | unset($params['page']); | ||
818 | |||
973 | header('Location: ?'.http_build_query($params)); | 819 | header('Location: ?'.http_build_query($params)); |
974 | exit; | 820 | exit; |
975 | } | 821 | } |
@@ -994,13 +840,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
994 | $tags = explode(' ', $params['searchtags']); | 840 | $tags = explode(' ', $params['searchtags']); |
995 | // Remove value from array $tags. | 841 | // Remove value from array $tags. |
996 | $tags = array_diff($tags, array($_GET['removetag'])); | 842 | $tags = array_diff($tags, array($_GET['removetag'])); |
997 | $params['searchtags'] = implode(' ',$tags); | 843 | $params['searchtags'] = implode(' ', $tags); |
998 | 844 | ||
999 | if (empty($params['searchtags'])) { | 845 | if (empty($params['searchtags'])) { |
1000 | unset($params['searchtags']); | 846 | unset($params['searchtags']); |
1001 | } | 847 | } |
1002 | 848 | ||
1003 | unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) | 849 | // We also remove page (keeping the same page has no sense, since |
850 | // the results are different) | ||
851 | unset($params['page']); | ||
1004 | } | 852 | } |
1005 | header('Location: ?'.http_build_query($params)); | 853 | header('Location: ?'.http_build_query($params)); |
1006 | exit; | 854 | exit; |
@@ -1022,15 +870,26 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1022 | } | 870 | } |
1023 | 871 | ||
1024 | // -------- User wants to see only private links (toggle) | 872 | // -------- User wants to see only private links (toggle) |
1025 | if (isset($_GET['privateonly'])) { | 873 | if (isset($_GET['visibility'])) { |
1026 | if (empty($_SESSION['privateonly'])) { | 874 | if ($_GET['visibility'] === 'private') { |
1027 | $_SESSION['privateonly'] = 1; // See only private links | 875 | // Visibility not set or not already private, set private, otherwise reset it |
1028 | } else { | 876 | if (empty($_SESSION['visibility']) || $_SESSION['visibility'] !== 'private') { |
1029 | unset($_SESSION['privateonly']); // See all links | 877 | // See only private links |
878 | $_SESSION['visibility'] = 'private'; | ||
879 | } else { | ||
880 | unset($_SESSION['visibility']); | ||
881 | } | ||
882 | } elseif ($_GET['visibility'] === 'public') { | ||
883 | if (empty($_SESSION['visibility']) || $_SESSION['visibility'] !== 'public') { | ||
884 | // See only public links | ||
885 | $_SESSION['visibility'] = 'public'; | ||
886 | } else { | ||
887 | unset($_SESSION['visibility']); | ||
888 | } | ||
1030 | } | 889 | } |
1031 | 890 | ||
1032 | if (! empty($_SERVER['HTTP_REFERER'])) { | 891 | if (! empty($_SERVER['HTTP_REFERER'])) { |
1033 | $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly')); | 892 | $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('visibility')); |
1034 | } else { | 893 | } else { |
1035 | $location = '?'; | 894 | $location = '?'; |
1036 | } | 895 | } |
@@ -1052,12 +911,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1052 | } | 911 | } |
1053 | 912 | ||
1054 | // -------- Handle other actions allowed for non-logged in users: | 913 | // -------- Handle other actions allowed for non-logged in users: |
1055 | if (!isLoggedIn()) | 914 | if (!$loginManager->isLoggedIn()) { |
1056 | { | ||
1057 | // User tries to post new link but is not logged in: | 915 | // User tries to post new link but is not logged in: |
1058 | // Show login screen, then redirect to ?post=... | 916 | // Show login screen, then redirect to ?post=... |
1059 | if (isset($_GET['post'])) | 917 | if (isset($_GET['post'])) { |
1060 | { | ||
1061 | header( // Redirect to login page, then back to post link. | 918 | header( // Redirect to login page, then back to post link. |
1062 | 'Location: ?do=login&post='.urlencode($_GET['post']). | 919 | 'Location: ?do=login&post='.urlencode($_GET['post']). |
1063 | (!empty($_GET['title'])?'&title='.urlencode($_GET['title']):''). | 920 | (!empty($_GET['title'])?'&title='.urlencode($_GET['title']):''). |
@@ -1068,7 +925,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1068 | exit; | 925 | exit; |
1069 | } | 926 | } |
1070 | 927 | ||
1071 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); | 928 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); |
1072 | if (isset($_GET['edit_link'])) { | 929 | if (isset($_GET['edit_link'])) { |
1073 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); | 930 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); |
1074 | exit; | 931 | exit; |
@@ -1080,8 +937,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1080 | // -------- All other functions are reserved for the registered user: | 937 | // -------- All other functions are reserved for the registered user: |
1081 | 938 | ||
1082 | // -------- Display the Tools menu if requested (import/export/bookmarklet...) | 939 | // -------- Display the Tools menu if requested (import/export/bookmarklet...) |
1083 | if ($targetPage == Router::$PAGE_TOOLS) | 940 | if ($targetPage == Router::$PAGE_TOOLS) { |
1084 | { | ||
1085 | $data = [ | 941 | $data = [ |
1086 | 'pageabsaddr' => index_url($_SERVER), | 942 | 'pageabsaddr' => index_url($_SERVER), |
1087 | 'sslenabled' => is_https($_SERVER), | 943 | 'sslenabled' => is_https($_SERVER), |
@@ -1092,35 +948,46 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1092 | $PAGE->assign($key, $value); | 948 | $PAGE->assign($key, $value); |
1093 | } | 949 | } |
1094 | 950 | ||
951 | $PAGE->assign('pagetitle', t('Tools') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1095 | $PAGE->renderPage('tools'); | 952 | $PAGE->renderPage('tools'); |
1096 | exit; | 953 | exit; |
1097 | } | 954 | } |
1098 | 955 | ||
1099 | // -------- User wants to change his/her password. | 956 | // -------- User wants to change his/her password. |
1100 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) | 957 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) { |
1101 | { | ||
1102 | if ($conf->get('security.open_shaarli')) { | 958 | if ($conf->get('security.open_shaarli')) { |
1103 | die(t('You are not supposed to change a password on an Open Shaarli.')); | 959 | die(t('You are not supposed to change a password on an Open Shaarli.')); |
1104 | } | 960 | } |
1105 | 961 | ||
1106 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) | 962 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) { |
1107 | { | 963 | if (!$sessionManager->checkToken($_POST['token'])) { |
1108 | if (!$sessionManager->checkToken($_POST['token'])) die(t('Wrong token.')); // Go away! | 964 | die(t('Wrong token.')); // Go away! |
965 | } | ||
1109 | 966 | ||
1110 | // Make sure old password is correct. | 967 | // Make sure old password is correct. |
1111 | $oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')); | 968 | $oldhash = sha1( |
1112 | if ($oldhash!= $conf->get('credentials.hash')) { | 969 | $_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt') |
1113 | echo '<script>alert("'. t('The old password is not correct.') .'");document.location=\'?do=changepasswd\';</script>'; | 970 | ); |
971 | if ($oldhash != $conf->get('credentials.hash')) { | ||
972 | echo '<script>alert("' | ||
973 | . t('The old password is not correct.') | ||
974 | .'");document.location=\'?do=changepasswd\';</script>'; | ||
1114 | exit; | 975 | exit; |
1115 | } | 976 | } |
1116 | // Save new password | 977 | // Save new password |
1117 | // Salt renders rainbow-tables attacks useless. | 978 | // Salt renders rainbow-tables attacks useless. |
1118 | $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); | 979 | $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); |
1119 | $conf->set('credentials.hash', sha1($_POST['setpassword'] . $conf->get('credentials.login') . $conf->get('credentials.salt'))); | 980 | $conf->set( |
981 | 'credentials.hash', | ||
982 | sha1( | ||
983 | $_POST['setpassword'] | ||
984 | . $conf->get('credentials.login') | ||
985 | . $conf->get('credentials.salt') | ||
986 | ) | ||
987 | ); | ||
1120 | try { | 988 | try { |
1121 | $conf->write(isLoggedIn()); | 989 | $conf->write($loginManager->isLoggedIn()); |
1122 | } | 990 | } catch (Exception $e) { |
1123 | catch(Exception $e) { | ||
1124 | error_log( | 991 | error_log( |
1125 | 'ERROR while writing config file after changing password.' . PHP_EOL . | 992 | 'ERROR while writing config file after changing password.' . PHP_EOL . |
1126 | $e->getMessage() | 993 | $e->getMessage() |
@@ -1132,19 +999,17 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1132 | } | 999 | } |
1133 | echo '<script>alert("'. t('Your password has been changed') .'");document.location=\'?do=tools\';</script>'; | 1000 | echo '<script>alert("'. t('Your password has been changed') .'");document.location=\'?do=tools\';</script>'; |
1134 | exit; | 1001 | exit; |
1135 | } | 1002 | } else { |
1136 | else // show the change password form. | 1003 | // show the change password form. |
1137 | { | 1004 | $PAGE->assign('pagetitle', t('Change password') .' - '. $conf->get('general.title', 'Shaarli')); |
1138 | $PAGE->renderPage('changepassword'); | 1005 | $PAGE->renderPage('changepassword'); |
1139 | exit; | 1006 | exit; |
1140 | } | 1007 | } |
1141 | } | 1008 | } |
1142 | 1009 | ||
1143 | // -------- User wants to change configuration | 1010 | // -------- User wants to change configuration |
1144 | if ($targetPage == Router::$PAGE_CONFIGURE) | 1011 | if ($targetPage == Router::$PAGE_CONFIGURE) { |
1145 | { | 1012 | if (!empty($_POST['title'])) { |
1146 | if (!empty($_POST['title']) ) | ||
1147 | { | ||
1148 | if (!$sessionManager->checkToken($_POST['token'])) { | 1013 | if (!$sessionManager->checkToken($_POST['token'])) { |
1149 | die(t('Wrong token.')); // Go away! | 1014 | die(t('Wrong token.')); // Go away! |
1150 | } | 1015 | } |
@@ -1158,7 +1023,6 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1158 | $conf->set('general.title', escape($_POST['title'])); | 1023 | $conf->set('general.title', escape($_POST['title'])); |
1159 | $conf->set('general.header_link', escape($_POST['titleLink'])); | 1024 | $conf->set('general.header_link', escape($_POST['titleLink'])); |
1160 | $conf->set('resource.theme', escape($_POST['theme'])); | 1025 | $conf->set('resource.theme', escape($_POST['theme'])); |
1161 | $conf->set('redirector.url', escape($_POST['redirector'])); | ||
1162 | $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); | 1026 | $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); |
1163 | $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); | 1027 | $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); |
1164 | $conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks'])); | 1028 | $conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks'])); |
@@ -1168,12 +1032,22 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1168 | $conf->set('api.secret', escape($_POST['apiSecret'])); | 1032 | $conf->set('api.secret', escape($_POST['apiSecret'])); |
1169 | $conf->set('translation.language', escape($_POST['language'])); | 1033 | $conf->set('translation.language', escape($_POST['language'])); |
1170 | 1034 | ||
1035 | $thumbnailsMode = extension_loaded('gd') ? $_POST['enableThumbnails'] : Thumbnailer::MODE_NONE; | ||
1036 | if ($thumbnailsMode !== Thumbnailer::MODE_NONE | ||
1037 | && $thumbnailsMode !== $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) | ||
1038 | ) { | ||
1039 | $_SESSION['warnings'][] = t( | ||
1040 | 'You have enabled or changed thumbnails mode. ' | ||
1041 | .'<a href="?do=thumbs_update">Please synchronize them</a>.' | ||
1042 | ); | ||
1043 | } | ||
1044 | $conf->set('thumbnails.mode', $thumbnailsMode); | ||
1045 | |||
1171 | try { | 1046 | try { |
1172 | $conf->write(isLoggedIn()); | 1047 | $conf->write($loginManager->isLoggedIn()); |
1173 | $history->updateSettings(); | 1048 | $history->updateSettings(); |
1174 | invalidateCaches($conf->get('resource.page_cache')); | 1049 | invalidateCaches($conf->get('resource.page_cache')); |
1175 | } | 1050 | } catch (Exception $e) { |
1176 | catch(Exception $e) { | ||
1177 | error_log( | 1051 | error_log( |
1178 | 'ERROR while writing config file after configuration update.' . PHP_EOL . | 1052 | 'ERROR while writing config file after configuration update.' . PHP_EOL . |
1179 | $e->getMessage() | 1053 | $e->getMessage() |
@@ -1185,13 +1059,11 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1185 | } | 1059 | } |
1186 | echo '<script>alert("'. t('Configuration was saved.') .'");document.location=\'?do=configure\';</script>'; | 1060 | echo '<script>alert("'. t('Configuration was saved.') .'");document.location=\'?do=configure\';</script>'; |
1187 | exit; | 1061 | exit; |
1188 | } | 1062 | } else { |
1189 | else // Show the configuration form. | 1063 | // Show the configuration form. |
1190 | { | ||
1191 | $PAGE->assign('title', $conf->get('general.title')); | 1064 | $PAGE->assign('title', $conf->get('general.title')); |
1192 | $PAGE->assign('theme', $conf->get('resource.theme')); | 1065 | $PAGE->assign('theme', $conf->get('resource.theme')); |
1193 | $PAGE->assign('theme_available', ThemeUtils::getThemes($conf->get('resource.raintpl_tpl'))); | 1066 | $PAGE->assign('theme_available', ThemeUtils::getThemes($conf->get('resource.raintpl_tpl'))); |
1194 | $PAGE->assign('redirector', $conf->get('redirector.url')); | ||
1195 | list($continents, $cities) = generateTimeZoneData( | 1067 | list($continents, $cities) = generateTimeZoneData( |
1196 | timezone_identifiers_list(), | 1068 | timezone_identifiers_list(), |
1197 | $conf->get('general.timezone') | 1069 | $conf->get('general.timezone') |
@@ -1207,16 +1079,19 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1207 | $PAGE->assign('api_secret', $conf->get('api.secret')); | 1079 | $PAGE->assign('api_secret', $conf->get('api.secret')); |
1208 | $PAGE->assign('languages', Languages::getAvailableLanguages()); | 1080 | $PAGE->assign('languages', Languages::getAvailableLanguages()); |
1209 | $PAGE->assign('language', $conf->get('translation.language')); | 1081 | $PAGE->assign('language', $conf->get('translation.language')); |
1082 | $PAGE->assign('gd_enabled', extension_loaded('gd')); | ||
1083 | $PAGE->assign('thumbnails_mode', $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE)); | ||
1084 | $PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1210 | $PAGE->renderPage('configure'); | 1085 | $PAGE->renderPage('configure'); |
1211 | exit; | 1086 | exit; |
1212 | } | 1087 | } |
1213 | } | 1088 | } |
1214 | 1089 | ||
1215 | // -------- User wants to rename a tag or delete it | 1090 | // -------- User wants to rename a tag or delete it |
1216 | if ($targetPage == Router::$PAGE_CHANGETAG) | 1091 | if ($targetPage == Router::$PAGE_CHANGETAG) { |
1217 | { | ||
1218 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { | 1092 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { |
1219 | $PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : ''); | 1093 | $PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : ''); |
1094 | $PAGE->assign('pagetitle', t('Manage tags') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1220 | $PAGE->renderPage('changetag'); | 1095 | $PAGE->renderPage('changetag'); |
1221 | exit; | 1096 | exit; |
1222 | } | 1097 | } |
@@ -1225,7 +1100,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1225 | die(t('Wrong token.')); | 1100 | die(t('Wrong token.')); |
1226 | } | 1101 | } |
1227 | 1102 | ||
1228 | $alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), escape($_POST['totag'])); | 1103 | $toTag = isset($_POST['totag']) ? escape($_POST['totag']) : null; |
1104 | $alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), $toTag); | ||
1229 | $LINKSDB->save($conf->get('resource.page_cache')); | 1105 | $LINKSDB->save($conf->get('resource.page_cache')); |
1230 | foreach ($alteredLinks as $link) { | 1106 | foreach ($alteredLinks as $link) { |
1231 | $history->updateLink($link); | 1107 | $history->updateLink($link); |
@@ -1241,15 +1117,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1241 | } | 1117 | } |
1242 | 1118 | ||
1243 | // -------- User wants to add a link without using the bookmarklet: Show form. | 1119 | // -------- User wants to add a link without using the bookmarklet: Show form. |
1244 | if ($targetPage == Router::$PAGE_ADDLINK) | 1120 | if ($targetPage == Router::$PAGE_ADDLINK) { |
1245 | { | 1121 | $PAGE->assign('pagetitle', t('Shaare a new link') .' - '. $conf->get('general.title', 'Shaarli')); |
1246 | $PAGE->renderPage('addlink'); | 1122 | $PAGE->renderPage('addlink'); |
1247 | exit; | 1123 | exit; |
1248 | } | 1124 | } |
1249 | 1125 | ||
1250 | // -------- User clicked the "Save" button when editing a link: Save link to database. | 1126 | // -------- User clicked the "Save" button when editing a link: Save link to database. |
1251 | if (isset($_POST['save_edit'])) | 1127 | if (isset($_POST['save_edit'])) { |
1252 | { | ||
1253 | // Go away! | 1128 | // Go away! |
1254 | if (! $sessionManager->checkToken($_POST['token'])) { | 1129 | if (! $sessionManager->checkToken($_POST['token'])) { |
1255 | die(t('Wrong token.')); | 1130 | die(t('Wrong token.')); |
@@ -1260,7 +1135,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1260 | // Linkdate is kept here to: | 1135 | // Linkdate is kept here to: |
1261 | // - use the same permalink for notes as they're displayed when creating them | 1136 | // - use the same permalink for notes as they're displayed when creating them |
1262 | // - let users hack creation date of their posts | 1137 | // - let users hack creation date of their posts |
1263 | // See: https://shaarli.readthedocs.io/en/master/Various-hacks/#changing-the-timestamp-for-a-shaare | 1138 | // See: https://shaarli.readthedocs.io/en/master/guides/various-hacks/#changing-the-timestamp-for-a-shaare |
1264 | $linkdate = escape($_POST['lf_linkdate']); | 1139 | $linkdate = escape($_POST['lf_linkdate']); |
1265 | if (isset($LINKSDB[$id])) { | 1140 | if (isset($LINKSDB[$id])) { |
1266 | // Edit | 1141 | // Edit |
@@ -1305,6 +1180,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1305 | $link['title'] = $link['url']; | 1180 | $link['title'] = $link['url']; |
1306 | } | 1181 | } |
1307 | 1182 | ||
1183 | if ($conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE) { | ||
1184 | $thumbnailer = new Thumbnailer($conf); | ||
1185 | $link['thumbnail'] = $thumbnailer->get($url); | ||
1186 | } | ||
1187 | |||
1188 | $link['sticky'] = isset($link['sticky']) ? $link['sticky'] : false; | ||
1189 | |||
1308 | $pluginManager->executeHooks('save_link', $link); | 1190 | $pluginManager->executeHooks('save_link', $link); |
1309 | 1191 | ||
1310 | $LINKSDB[$id] = $link; | 1192 | $LINKSDB[$id] = $link; |
@@ -1331,14 +1213,16 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1331 | } | 1213 | } |
1332 | 1214 | ||
1333 | // -------- User clicked the "Cancel" button when editing a link. | 1215 | // -------- User clicked the "Cancel" button when editing a link. |
1334 | if (isset($_POST['cancel_edit'])) | 1216 | if (isset($_POST['cancel_edit'])) { |
1335 | { | ||
1336 | $id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : false; | 1217 | $id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : false; |
1337 | if (! isset($LINKSDB[$id])) { | 1218 | if (! isset($LINKSDB[$id])) { |
1338 | header('Location: ?'); | 1219 | header('Location: ?'); |
1339 | } | 1220 | } |
1340 | // If we are called from the bookmarklet, we must close the popup: | 1221 | // If we are called from the bookmarklet, we must close the popup: |
1341 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1222 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { |
1223 | echo '<script>self.close();</script>'; | ||
1224 | exit; | ||
1225 | } | ||
1342 | $link = $LINKSDB[$id]; | 1226 | $link = $LINKSDB[$id]; |
1343 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); | 1227 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); |
1344 | // Scroll to the link which has been edited. | 1228 | // Scroll to the link which has been edited. |
@@ -1349,8 +1233,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1349 | } | 1233 | } |
1350 | 1234 | ||
1351 | // -------- User clicked the "Delete" button when editing a link: Delete link from database. | 1235 | // -------- User clicked the "Delete" button when editing a link: Delete link from database. |
1352 | if ($targetPage == Router::$PAGE_DELETELINK) | 1236 | if ($targetPage == Router::$PAGE_DELETELINK) { |
1353 | { | ||
1354 | if (! $sessionManager->checkToken($_GET['token'])) { | 1237 | if (! $sessionManager->checkToken($_GET['token'])) { |
1355 | die(t('Wrong token.')); | 1238 | die(t('Wrong token.')); |
1356 | } | 1239 | } |
@@ -1364,28 +1247,31 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1364 | $ids = [$ids]; | 1247 | $ids = [$ids]; |
1365 | } | 1248 | } |
1366 | // assert at least one id is given | 1249 | // assert at least one id is given |
1367 | if(!count($ids)){ | 1250 | if (!count($ids)) { |
1368 | die('no id provided'); | 1251 | die('no id provided'); |
1369 | } | 1252 | } |
1370 | foreach ($ids as $id) { | 1253 | foreach ($ids as $id) { |
1371 | $id = (int) escape($id); | 1254 | $id = (int) escape($id); |
1372 | $link = $LINKSDB[$id]; | 1255 | $link = $LINKSDB[$id]; |
1373 | $pluginManager->executeHooks('delete_link', $link); | 1256 | $pluginManager->executeHooks('delete_link', $link); |
1257 | $history->deleteLink($link); | ||
1374 | unset($LINKSDB[$id]); | 1258 | unset($LINKSDB[$id]); |
1375 | } | 1259 | } |
1376 | $LINKSDB->save($conf->get('resource.page_cache')); // save to disk | 1260 | $LINKSDB->save($conf->get('resource.page_cache')); // save to disk |
1377 | $history->deleteLink($link); | ||
1378 | 1261 | ||
1379 | // If we are called from the bookmarklet, we must close the popup: | 1262 | // If we are called from the bookmarklet, we must close the popup: |
1380 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1263 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { |
1264 | echo '<script>self.close();</script>'; | ||
1265 | exit; | ||
1266 | } | ||
1381 | 1267 | ||
1382 | $location = '?'; | 1268 | $location = '?'; |
1383 | if (isset($_SERVER['HTTP_REFERER'])) { | 1269 | if (isset($_SERVER['HTTP_REFERER'])) { |
1384 | // Don't redirect to where we were previously if it was a permalink or an edit_link, because it would 404. | 1270 | // Don't redirect to where we were previously if it was a permalink or an edit_link, because it would 404. |
1385 | $location = generateLocation( | 1271 | $location = generateLocation( |
1386 | $_SERVER['HTTP_REFERER'], | 1272 | $_SERVER['HTTP_REFERER'], |
1387 | $_SERVER['HTTP_HOST'], | 1273 | $_SERVER['HTTP_HOST'], |
1388 | ['delete_link', 'edit_link', $link['shorturl']] | 1274 | ['delete_link', 'edit_link', $link['shorturl']] |
1389 | ); | 1275 | ); |
1390 | } | 1276 | } |
1391 | 1277 | ||
@@ -1394,11 +1280,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1394 | } | 1280 | } |
1395 | 1281 | ||
1396 | // -------- User clicked the "EDIT" button on a link: Display link edit form. | 1282 | // -------- User clicked the "EDIT" button on a link: Display link edit form. |
1397 | if (isset($_GET['edit_link'])) | 1283 | if (isset($_GET['edit_link'])) { |
1398 | { | ||
1399 | $id = (int) escape($_GET['edit_link']); | 1284 | $id = (int) escape($_GET['edit_link']); |
1400 | $link = $LINKSDB[$id]; // Read database | 1285 | $link = $LINKSDB[$id]; // Read database |
1401 | if (!$link) { header('Location: ?'); exit; } // Link not found in database. | 1286 | if (!$link) { |
1287 | header('Location: ?'); | ||
1288 | exit; | ||
1289 | } // Link not found in database. | ||
1402 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); | 1290 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); |
1403 | $data = array( | 1291 | $data = array( |
1404 | 'link' => $link, | 1292 | 'link' => $link, |
@@ -1412,6 +1300,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1412 | $PAGE->assign($key, $value); | 1300 | $PAGE->assign($key, $value); |
1413 | } | 1301 | } |
1414 | 1302 | ||
1303 | $PAGE->assign('pagetitle', t('Edit') .' '. t('Shaare') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1415 | $PAGE->renderPage('editlink'); | 1304 | $PAGE->renderPage('editlink'); |
1416 | exit; | 1305 | exit; |
1417 | } | 1306 | } |
@@ -1423,8 +1312,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1423 | $link_is_new = false; | 1312 | $link_is_new = false; |
1424 | // Check if URL is not already in database (in this case, we will edit the existing link) | 1313 | // Check if URL is not already in database (in this case, we will edit the existing link) |
1425 | $link = $LINKSDB->getLinkFromUrl($url); | 1314 | $link = $LINKSDB->getLinkFromUrl($url); |
1426 | if (! $link) | 1315 | if (! $link) { |
1427 | { | ||
1428 | $link_is_new = true; | 1316 | $link_is_new = true; |
1429 | $linkdate = strval(date(LinkDB::LINK_DATE_FORMAT)); | 1317 | $linkdate = strval(date(LinkDB::LINK_DATE_FORMAT)); |
1430 | // Get title if it was provided in URL (by the bookmarklet). | 1318 | // Get title if it was provided in URL (by the bookmarklet). |
@@ -1433,11 +1321,18 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1433 | $description = empty($_GET['description']) ? '' : escape($_GET['description']); | 1321 | $description = empty($_GET['description']) ? '' : escape($_GET['description']); |
1434 | $tags = empty($_GET['tags']) ? '' : escape($_GET['tags']); | 1322 | $tags = empty($_GET['tags']) ? '' : escape($_GET['tags']); |
1435 | $private = !empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0; | 1323 | $private = !empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0; |
1436 | // If this is an HTTP(S) link, we try go get the page to extract the title (otherwise we will to straight to the edit form.) | 1324 | |
1325 | // If this is an HTTP(S) link, we try go get the page to extract | ||
1326 | // the title (otherwise we will to straight to the edit form.) | ||
1437 | if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { | 1327 | if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { |
1438 | // Short timeout to keep the application responsive | 1328 | // Short timeout to keep the application responsive |
1439 | // The callback will fill $charset and $title with data from the downloaded page. | 1329 | // The callback will fill $charset and $title with data from the downloaded page. |
1440 | get_http_response($url, 25, 4194304, get_curl_download_callback($charset, $title)); | 1330 | get_http_response( |
1331 | $url, | ||
1332 | $conf->get('general.download_timeout', 30), | ||
1333 | $conf->get('general.download_max_size', 4194304), | ||
1334 | get_curl_download_callback($charset, $title) | ||
1335 | ); | ||
1441 | if (! empty($title) && strtolower($charset) != 'utf-8') { | 1336 | if (! empty($title) && strtolower($charset) != 'utf-8') { |
1442 | $title = mb_convert_encoding($title, 'utf-8', $charset); | 1337 | $title = mb_convert_encoding($title, 'utf-8', $charset); |
1443 | } | 1338 | } |
@@ -1476,14 +1371,35 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1476 | $PAGE->assign($key, $value); | 1371 | $PAGE->assign($key, $value); |
1477 | } | 1372 | } |
1478 | 1373 | ||
1374 | $PAGE->assign('pagetitle', t('Shaare') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1479 | $PAGE->renderPage('editlink'); | 1375 | $PAGE->renderPage('editlink'); |
1480 | exit; | 1376 | exit; |
1481 | } | 1377 | } |
1482 | 1378 | ||
1379 | if ($targetPage == Router::$PAGE_PINLINK) { | ||
1380 | if (! isset($_GET['id']) || empty($LINKSDB[$_GET['id']])) { | ||
1381 | // FIXME! Use a proper error system. | ||
1382 | $msg = t('Invalid link ID provided'); | ||
1383 | echo '<script>alert("'. $msg .'");document.location=\''. index_url($_SERVER) .'\';</script>'; | ||
1384 | exit; | ||
1385 | } | ||
1386 | if (! $sessionManager->checkToken($_GET['token'])) { | ||
1387 | die('Wrong token.'); | ||
1388 | } | ||
1389 | |||
1390 | $link = $LINKSDB[$_GET['id']]; | ||
1391 | $link['sticky'] = ! $link['sticky']; | ||
1392 | $LINKSDB[(int) $_GET['id']] = $link; | ||
1393 | $LINKSDB->save($conf->get('resource.page_cache')); | ||
1394 | header('Location: '.index_url($_SERVER)); | ||
1395 | exit; | ||
1396 | } | ||
1397 | |||
1483 | if ($targetPage == Router::$PAGE_EXPORT) { | 1398 | if ($targetPage == Router::$PAGE_EXPORT) { |
1484 | // Export links as a Netscape Bookmarks file | 1399 | // Export links as a Netscape Bookmarks file |
1485 | 1400 | ||
1486 | if (empty($_GET['selection'])) { | 1401 | if (empty($_GET['selection'])) { |
1402 | $PAGE->assign('pagetitle', t('Export') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1487 | $PAGE->renderPage('export'); | 1403 | $PAGE->renderPage('export'); |
1488 | exit; | 1404 | exit; |
1489 | } | 1405 | } |
@@ -1515,7 +1431,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1515 | header('Content-Type: text/html; charset=utf-8'); | 1431 | header('Content-Type: text/html; charset=utf-8'); |
1516 | header( | 1432 | header( |
1517 | 'Content-disposition: attachment; filename=bookmarks_' | 1433 | 'Content-disposition: attachment; filename=bookmarks_' |
1518 | .$selection.'_'.$now->format(LinkDB::LINK_DATE_FORMAT).'.html' | 1434 | .$selection.'_'.$now->format(LinkDB::LINK_DATE_FORMAT).'.html' |
1519 | ); | 1435 | ); |
1520 | $PAGE->assign('date', $now->format(DateTime::RFC822)); | 1436 | $PAGE->assign('date', $now->format(DateTime::RFC822)); |
1521 | $PAGE->assign('eol', PHP_EOL); | 1437 | $PAGE->assign('eol', PHP_EOL); |
@@ -1545,6 +1461,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1545 | true | 1461 | true |
1546 | ) | 1462 | ) |
1547 | ); | 1463 | ); |
1464 | $PAGE->assign('pagetitle', t('Import') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1548 | $PAGE->renderPage('import'); | 1465 | $PAGE->renderPage('import'); |
1549 | exit; | 1466 | exit; |
1550 | } | 1467 | } |
@@ -1582,17 +1499,24 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1582 | $pluginMeta = $pluginManager->getPluginsMeta(); | 1499 | $pluginMeta = $pluginManager->getPluginsMeta(); |
1583 | 1500 | ||
1584 | // Split plugins into 2 arrays: ordered enabled plugins and disabled. | 1501 | // Split plugins into 2 arrays: ordered enabled plugins and disabled. |
1585 | $enabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] !== false; }); | 1502 | $enabledPlugins = array_filter($pluginMeta, function ($v) { |
1503 | return $v['order'] !== false; | ||
1504 | }); | ||
1586 | // Load parameters. | 1505 | // Load parameters. |
1587 | $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $conf->get('plugins', array())); | 1506 | $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $conf->get('plugins', array())); |
1588 | uasort( | 1507 | uasort( |
1589 | $enabledPlugins, | 1508 | $enabledPlugins, |
1590 | function($a, $b) { return $a['order'] - $b['order']; } | 1509 | function ($a, $b) { |
1510 | return $a['order'] - $b['order']; | ||
1511 | } | ||
1591 | ); | 1512 | ); |
1592 | $disabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] === false; }); | 1513 | $disabledPlugins = array_filter($pluginMeta, function ($v) { |
1514 | return $v['order'] === false; | ||
1515 | }); | ||
1593 | 1516 | ||
1594 | $PAGE->assign('enabledPlugins', $enabledPlugins); | 1517 | $PAGE->assign('enabledPlugins', $enabledPlugins); |
1595 | $PAGE->assign('disabledPlugins', $disabledPlugins); | 1518 | $PAGE->assign('disabledPlugins', $disabledPlugins); |
1519 | $PAGE->assign('pagetitle', t('Plugin administration') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1596 | $PAGE->renderPage('pluginsadmin'); | 1520 | $PAGE->renderPage('pluginsadmin'); |
1597 | exit; | 1521 | exit; |
1598 | } | 1522 | } |
@@ -1605,21 +1529,23 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1605 | foreach ($_POST as $param => $value) { | 1529 | foreach ($_POST as $param => $value) { |
1606 | $conf->set('plugins.'. $param, escape($value)); | 1530 | $conf->set('plugins.'. $param, escape($value)); |
1607 | } | 1531 | } |
1608 | } | 1532 | } else { |
1609 | else { | ||
1610 | $conf->set('general.enabled_plugins', save_plugin_config($_POST)); | 1533 | $conf->set('general.enabled_plugins', save_plugin_config($_POST)); |
1611 | } | 1534 | } |
1612 | $conf->write(isLoggedIn()); | 1535 | $conf->write($loginManager->isLoggedIn()); |
1613 | $history->updateSettings(); | 1536 | $history->updateSettings(); |
1614 | } | 1537 | } catch (Exception $e) { |
1615 | catch (Exception $e) { | ||
1616 | error_log( | 1538 | error_log( |
1617 | 'ERROR while saving plugin configuration:.' . PHP_EOL . | 1539 | 'ERROR while saving plugin configuration:.' . PHP_EOL . |
1618 | $e->getMessage() | 1540 | $e->getMessage() |
1619 | ); | 1541 | ); |
1620 | 1542 | ||
1621 | // TODO: do not handle exceptions/errors in JS. | 1543 | // TODO: do not handle exceptions/errors in JS. |
1622 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do='. Router::$PAGE_PLUGINSADMIN .'\';</script>'; | 1544 | echo '<script>alert("' |
1545 | . $e->getMessage() | ||
1546 | .'");document.location=\'?do=' | ||
1547 | . Router::$PAGE_PLUGINSADMIN | ||
1548 | .'\';</script>'; | ||
1623 | exit; | 1549 | exit; |
1624 | } | 1550 | } |
1625 | header('Location: ?do='. Router::$PAGE_PLUGINSADMIN); | 1551 | header('Location: ?do='. Router::$PAGE_PLUGINSADMIN); |
@@ -1633,8 +1559,45 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1633 | exit; | 1559 | exit; |
1634 | } | 1560 | } |
1635 | 1561 | ||
1562 | // -------- Thumbnails Update | ||
1563 | if ($targetPage == Router::$PAGE_THUMBS_UPDATE) { | ||
1564 | $ids = []; | ||
1565 | foreach ($LINKSDB as $link) { | ||
1566 | // A note or not HTTP(S) | ||
1567 | if ($link['url'][0] === '?' || ! startsWith(strtolower($link['url']), 'http')) { | ||
1568 | continue; | ||
1569 | } | ||
1570 | $ids[] = $link['id']; | ||
1571 | } | ||
1572 | $PAGE->assign('ids', $ids); | ||
1573 | $PAGE->assign('pagetitle', t('Thumbnails update') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1574 | $PAGE->renderPage('thumbnails'); | ||
1575 | exit; | ||
1576 | } | ||
1577 | |||
1578 | // -------- Single Thumbnail Update | ||
1579 | if ($targetPage == Router::$AJAX_THUMB_UPDATE) { | ||
1580 | if (! isset($_POST['id']) || ! ctype_digit($_POST['id'])) { | ||
1581 | http_response_code(400); | ||
1582 | exit; | ||
1583 | } | ||
1584 | $id = (int) $_POST['id']; | ||
1585 | if (empty($LINKSDB[$id])) { | ||
1586 | http_response_code(404); | ||
1587 | exit; | ||
1588 | } | ||
1589 | $thumbnailer = new Thumbnailer($conf); | ||
1590 | $link = $LINKSDB[$id]; | ||
1591 | $link['thumbnail'] = $thumbnailer->get($link['url']); | ||
1592 | $LINKSDB[$id] = $link; | ||
1593 | $LINKSDB->save($conf->get('resource.page_cache')); | ||
1594 | |||
1595 | echo json_encode($link); | ||
1596 | exit; | ||
1597 | } | ||
1598 | |||
1636 | // -------- Otherwise, simply display search form and links: | 1599 | // -------- Otherwise, simply display search form and links: |
1637 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); | 1600 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); |
1638 | exit; | 1601 | exit; |
1639 | } | 1602 | } |
1640 | 1603 | ||
@@ -1646,8 +1609,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager) | |||
1646 | * @param LinkDB $LINKSDB LinkDB instance. | 1609 | * @param LinkDB $LINKSDB LinkDB instance. |
1647 | * @param ConfigManager $conf Configuration Manager instance. | 1610 | * @param ConfigManager $conf Configuration Manager instance. |
1648 | * @param PluginManager $pluginManager Plugin Manager instance. | 1611 | * @param PluginManager $pluginManager Plugin Manager instance. |
1612 | * @param LoginManager $loginManager LoginManager instance | ||
1649 | */ | 1613 | */ |
1650 | function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | 1614 | function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) |
1651 | { | 1615 | { |
1652 | // Used in templates | 1616 | // Used in templates |
1653 | if (isset($_GET['searchtags'])) { | 1617 | if (isset($_GET['searchtags'])) { |
@@ -1672,7 +1636,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1672 | } | 1636 | } |
1673 | } else { | 1637 | } else { |
1674 | // Filter links according search parameters. | 1638 | // Filter links according search parameters. |
1675 | $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; | 1639 | $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : ''; |
1676 | $request = [ | 1640 | $request = [ |
1677 | 'searchtags' => $searchtags, | 1641 | 'searchtags' => $searchtags, |
1678 | 'searchterm' => $searchterm, | 1642 | 'searchterm' => $searchterm, |
@@ -1686,8 +1650,6 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1686 | $keys[] = $key; | 1650 | $keys[] = $key; |
1687 | } | 1651 | } |
1688 | 1652 | ||
1689 | |||
1690 | |||
1691 | // Select articles according to paging. | 1653 | // Select articles according to paging. |
1692 | $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']); | 1654 | $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']); |
1693 | $pagecount = $pagecount == 0 ? 1 : $pagecount; | 1655 | $pagecount = $pagecount == 0 ? 1 : $pagecount; |
@@ -1697,9 +1659,14 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1697 | // Start index. | 1659 | // Start index. |
1698 | $i = ($page-1) * $_SESSION['LINKS_PER_PAGE']; | 1660 | $i = ($page-1) * $_SESSION['LINKS_PER_PAGE']; |
1699 | $end = $i + $_SESSION['LINKS_PER_PAGE']; | 1661 | $end = $i + $_SESSION['LINKS_PER_PAGE']; |
1662 | |||
1663 | $thumbnailsEnabled = $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE; | ||
1664 | if ($thumbnailsEnabled) { | ||
1665 | $thumbnailer = new Thumbnailer($conf); | ||
1666 | } | ||
1667 | |||
1700 | $linkDisp = array(); | 1668 | $linkDisp = array(); |
1701 | while ($i<$end && $i<count($keys)) | 1669 | while ($i<$end && $i<count($keys)) { |
1702 | { | ||
1703 | $link = $linksToDisplay[$keys[$i]]; | 1670 | $link = $linksToDisplay[$keys[$i]]; |
1704 | $link['description'] = format_description( | 1671 | $link['description'] = format_description( |
1705 | $link['description'], | 1672 | $link['description'], |
@@ -1717,9 +1684,21 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1717 | $taglist = preg_split('/\s+/', $link['tags'], -1, PREG_SPLIT_NO_EMPTY); | 1684 | $taglist = preg_split('/\s+/', $link['tags'], -1, PREG_SPLIT_NO_EMPTY); |
1718 | uasort($taglist, 'strcasecmp'); | 1685 | uasort($taglist, 'strcasecmp'); |
1719 | $link['taglist'] = $taglist; | 1686 | $link['taglist'] = $taglist; |
1687 | |||
1688 | // Logged in, thumbnails enabled, not a note, | ||
1689 | // and (never retrieved yet or no valid cache file) | ||
1690 | if ($loginManager->isLoggedIn() && $thumbnailsEnabled && $link['url'][0] != '?' | ||
1691 | && (! isset($link['thumbnail']) || ($link['thumbnail'] !== false && ! is_file($link['thumbnail']))) | ||
1692 | ) { | ||
1693 | $elem = $LINKSDB[$keys[$i]]; | ||
1694 | $elem['thumbnail'] = $thumbnailer->get($link['url']); | ||
1695 | $LINKSDB[$keys[$i]] = $elem; | ||
1696 | $updateDB = true; | ||
1697 | $link['thumbnail'] = $elem['thumbnail']; | ||
1698 | } | ||
1699 | |||
1720 | // Check for both signs of a note: starting with ? and 7 chars long. | 1700 | // Check for both signs of a note: starting with ? and 7 chars long. |
1721 | if ($link['url'][0] === '?' && | 1701 | if ($link['url'][0] === '?' && strlen($link['url']) === 7) { |
1722 | strlen($link['url']) === 7) { | ||
1723 | $link['url'] = index_url($_SERVER) . $link['url']; | 1702 | $link['url'] = index_url($_SERVER) . $link['url']; |
1724 | } | 1703 | } |
1725 | 1704 | ||
@@ -1727,6 +1706,11 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1727 | $i++; | 1706 | $i++; |
1728 | } | 1707 | } |
1729 | 1708 | ||
1709 | // If we retrieved new thumbnails, we update the database. | ||
1710 | if (!empty($updateDB)) { | ||
1711 | $LINKSDB->save($conf->get('resource.page_cache')); | ||
1712 | } | ||
1713 | |||
1730 | // Compute paging navigation | 1714 | // Compute paging navigation |
1731 | $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags); | 1715 | $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags); |
1732 | $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); | 1716 | $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); |
@@ -1748,7 +1732,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1748 | 'result_count' => count($linksToDisplay), | 1732 | 'result_count' => count($linksToDisplay), |
1749 | 'search_term' => $searchterm, | 1733 | 'search_term' => $searchterm, |
1750 | 'search_tags' => $searchtags, | 1734 | 'search_tags' => $searchtags, |
1751 | 'visibility' => ! empty($_SESSION['privateonly']) ? 'private' : '', | 1735 | 'visibility' => ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '', |
1752 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. | 1736 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. |
1753 | 'links' => $linkDisp, | 1737 | 'links' => $linkDisp, |
1754 | ); | 1738 | ); |
@@ -1756,9 +1740,19 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1756 | // If there is only a single link, we change on-the-fly the title of the page. | 1740 | // If there is only a single link, we change on-the-fly the title of the page. |
1757 | if (count($linksToDisplay) == 1) { | 1741 | if (count($linksToDisplay) == 1) { |
1758 | $data['pagetitle'] = $linksToDisplay[$keys[0]]['title'] .' - '. $conf->get('general.title'); | 1742 | $data['pagetitle'] = $linksToDisplay[$keys[0]]['title'] .' - '. $conf->get('general.title'); |
1743 | } elseif (! empty($searchterm) || ! empty($searchtags)) { | ||
1744 | $data['pagetitle'] = t('Search: '); | ||
1745 | $data['pagetitle'] .= ! empty($searchterm) ? $searchterm .' ' : ''; | ||
1746 | $bracketWrap = function ($tag) { | ||
1747 | return '['. $tag .']'; | ||
1748 | }; | ||
1749 | $data['pagetitle'] .= ! empty($searchtags) | ||
1750 | ? implode(' ', array_map($bracketWrap, preg_split('/\s+/', $searchtags))).' ' | ||
1751 | : ''; | ||
1752 | $data['pagetitle'] .= '- '. $conf->get('general.title'); | ||
1759 | } | 1753 | } |
1760 | 1754 | ||
1761 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); | 1755 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => $loginManager->isLoggedIn())); |
1762 | 1756 | ||
1763 | foreach ($data as $key => $value) { | 1757 | foreach ($data as $key => $value) { |
1764 | $PAGE->assign($key, $value); | 1758 | $PAGE->assign($key, $value); |
@@ -1768,210 +1762,26 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1768 | } | 1762 | } |
1769 | 1763 | ||
1770 | /** | 1764 | /** |
1771 | * Compute the thumbnail for a link. | ||
1772 | * | ||
1773 | * With a link to the original URL. | ||
1774 | * Understands various services (youtube.com...) | ||
1775 | * Input: $url = URL for which the thumbnail must be found. | ||
1776 | * $href = if provided, this URL will be followed instead of $url | ||
1777 | * Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) | ||
1778 | * Some of them may be missing. | ||
1779 | * Return an empty array if no thumbnail available. | ||
1780 | * | ||
1781 | * @param ConfigManager $conf Configuration Manager instance. | ||
1782 | * @param string $url | ||
1783 | * @param string|bool $href | ||
1784 | * | ||
1785 | * @return array | ||
1786 | */ | ||
1787 | function computeThumbnail($conf, $url, $href = false) | ||
1788 | { | ||
1789 | if (!$conf->get('thumbnail.enable_thumbnails')) return array(); | ||
1790 | if ($href==false) $href=$url; | ||
1791 | |||
1792 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. | ||
1793 | // (e.g. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg ) | ||
1794 | // ^^^^^^^^^^^ ^^^^^^^^^^^ | ||
1795 | $domain = parse_url($url,PHP_URL_HOST); | ||
1796 | if ($domain=='youtube.com' || $domain=='www.youtube.com') | ||
1797 | { | ||
1798 | parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail | ||
1799 | if (!empty($params['v'])) return array('src'=>'https://img.youtube.com/vi/'.$params['v'].'/default.jpg', | ||
1800 | 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail'); | ||
1801 | } | ||
1802 | if ($domain=='youtu.be') // Youtube short links | ||
1803 | { | ||
1804 | $path = parse_url($url,PHP_URL_PATH); | ||
1805 | return array('src'=>'https://img.youtube.com/vi'.$path.'/default.jpg', | ||
1806 | 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail'); | ||
1807 | } | ||
1808 | if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting | ||
1809 | { | ||
1810 | parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename. | ||
1811 | if (!empty($params) && !empty($params['img'])) return array('src'=>'http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']), | ||
1812 | 'href'=>$href,'style'=>'max-width:120px; max-height:150px','alt'=>'pix.toile-libre.org thumbnail'); | ||
1813 | } | ||
1814 | |||
1815 | if ($domain=='imgur.com') | ||
1816 | { | ||
1817 | $path = parse_url($url,PHP_URL_PATH); | ||
1818 | if (startsWith($path,'/a/')) return array(); // Thumbnails for albums are not available. | ||
1819 | if (startsWith($path,'/r/')) return array('src'=>'https://i.imgur.com/'.basename($path).'s.jpg', | ||
1820 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1821 | if (startsWith($path,'/gallery/')) return array('src'=>'https://i.imgur.com'.substr($path,8).'s.jpg', | ||
1822 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1823 | |||
1824 | if (substr_count($path,'/')==1) return array('src'=>'https://i.imgur.com/'.substr($path,1).'s.jpg', | ||
1825 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1826 | } | ||
1827 | if ($domain=='i.imgur.com') | ||
1828 | { | ||
1829 | $pi = pathinfo(parse_url($url,PHP_URL_PATH)); | ||
1830 | if (!empty($pi['filename'])) return array('src'=>'https://i.imgur.com/'.$pi['filename'].'s.jpg', | ||
1831 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1832 | } | ||
1833 | if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com') | ||
1834 | { | ||
1835 | if (strpos($url,'dailymotion.com/video/')!==false) | ||
1836 | { | ||
1837 | $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url); | ||
1838 | return array('src'=>$thumburl, | ||
1839 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'DailyMotion thumbnail'); | ||
1840 | } | ||
1841 | } | ||
1842 | if (endsWith($domain,'.imageshack.us')) | ||
1843 | { | ||
1844 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); | ||
1845 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') | ||
1846 | { | ||
1847 | $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext; | ||
1848 | return array('src'=>$thumburl, | ||
1849 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'imageshack.us thumbnail'); | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | // Some other hosts are SLOW AS HELL and usually require an extra HTTP request to get the thumbnail URL. | ||
1854 | // So we deport the thumbnail generation in order not to slow down page generation | ||
1855 | // (and we also cache the thumbnail) | ||
1856 | |||
1857 | if (! $conf->get('thumbnail.enable_localcache')) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache. | ||
1858 | |||
1859 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') | ||
1860 | || $domain=='vimeo.com' | ||
1861 | || $domain=='ted.com' || endsWith($domain,'.ted.com') | ||
1862 | || $domain=='xkcd.com' || endsWith($domain,'.xkcd.com') | ||
1863 | ) | ||
1864 | { | ||
1865 | if ($domain=='vimeo.com') | ||
1866 | { // Make sure this vimeo URL points to a video (/xxx... where xxx is numeric) | ||
1867 | $path = parse_url($url,PHP_URL_PATH); | ||
1868 | if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL. | ||
1869 | } | ||
1870 | if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) | ||
1871 | { // Make sure this URL points to a single comic (/xxx... where xxx is numeric) | ||
1872 | $path = parse_url($url,PHP_URL_PATH); | ||
1873 | if (!preg_match('!/\d+.+?!',$path)) return array(); | ||
1874 | } | ||
1875 | if ($domain=='ted.com' || endsWith($domain,'.ted.com')) | ||
1876 | { // Make sure this TED URL points to a video (/talks/...) | ||
1877 | $path = parse_url($url,PHP_URL_PATH); | ||
1878 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. | ||
1879 | } | ||
1880 | $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) | ||
1881 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | ||
1882 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | ||
1883 | } | ||
1884 | |||
1885 | // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif | ||
1886 | // Technically speaking, we should download ALL links and check their Content-Type to see if they are images. | ||
1887 | // But using the extension will do. | ||
1888 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); | ||
1889 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') | ||
1890 | { | ||
1891 | $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) | ||
1892 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | ||
1893 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | ||
1894 | } | ||
1895 | return array(); // No thumbnail. | ||
1896 | |||
1897 | } | ||
1898 | |||
1899 | |||
1900 | // Returns the HTML code to display a thumbnail for a link | ||
1901 | // with a link to the original URL. | ||
1902 | // Understands various services (youtube.com...) | ||
1903 | // Input: $url = URL for which the thumbnail must be found. | ||
1904 | // $href = if provided, this URL will be followed instead of $url | ||
1905 | // Returns '' if no thumbnail available. | ||
1906 | function thumbnail($url,$href=false) | ||
1907 | { | ||
1908 | // FIXME! | ||
1909 | global $conf; | ||
1910 | $t = computeThumbnail($conf, $url,$href); | ||
1911 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | ||
1912 | |||
1913 | $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"'; | ||
1914 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; | ||
1915 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; | ||
1916 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; | ||
1917 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; | ||
1918 | $html.='></a>'; | ||
1919 | return $html; | ||
1920 | } | ||
1921 | |||
1922 | // Returns the HTML code to display a thumbnail for a link | ||
1923 | // for the picture wall (using lazy image loading) | ||
1924 | // Understands various services (youtube.com...) | ||
1925 | // Input: $url = URL for which the thumbnail must be found. | ||
1926 | // $href = if provided, this URL will be followed instead of $url | ||
1927 | // Returns '' if no thumbnail available. | ||
1928 | function lazyThumbnail($conf, $url,$href=false) | ||
1929 | { | ||
1930 | // FIXME! | ||
1931 | global $conf; | ||
1932 | $t = computeThumbnail($conf, $url,$href); | ||
1933 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | ||
1934 | |||
1935 | $html='<a href="'.escape($t['href']).'">'; | ||
1936 | |||
1937 | // Lazy image | ||
1938 | $html.='<img class="b-lazy" src="#" data-src="'.escape($t['src']).'"'; | ||
1939 | |||
1940 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; | ||
1941 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; | ||
1942 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; | ||
1943 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; | ||
1944 | $html.='>'; | ||
1945 | |||
1946 | // No-JavaScript fallback. | ||
1947 | $html.='<noscript><img src="'.escape($t['src']).'"'; | ||
1948 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; | ||
1949 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; | ||
1950 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; | ||
1951 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; | ||
1952 | $html.='></noscript></a>'; | ||
1953 | |||
1954 | return $html; | ||
1955 | } | ||
1956 | |||
1957 | |||
1958 | /** | ||
1959 | * Installation | 1765 | * Installation |
1960 | * This function should NEVER be called if the file data/config.php exists. | 1766 | * This function should NEVER be called if the file data/config.php exists. |
1961 | * | 1767 | * |
1962 | * @param ConfigManager $conf Configuration Manager instance. | 1768 | * @param ConfigManager $conf Configuration Manager instance. |
1963 | * @param SessionManager $sessionManager SessionManager instance | 1769 | * @param SessionManager $sessionManager SessionManager instance |
1770 | * @param LoginManager $loginManager LoginManager instance | ||
1964 | */ | 1771 | */ |
1965 | function install($conf, $sessionManager) { | 1772 | function install($conf, $sessionManager, $loginManager) |
1773 | { | ||
1966 | // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. | 1774 | // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. |
1967 | if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); | 1775 | if (endsWith($_SERVER['HTTP_HOST'], '.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) { |
1776 | mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions', 0705); | ||
1777 | } | ||
1968 | 1778 | ||
1969 | 1779 | ||
1970 | // This part makes sure sessions works correctly. | 1780 | // This part makes sure sessions works correctly. |
1971 | // (Because on some hosts, session.save_path may not be set correctly, | 1781 | // (Because on some hosts, session.save_path may not be set correctly, |
1972 | // or we may not have write access to it.) | 1782 | // or we may not have write access to it.) |
1973 | if (isset($_GET['test_session']) && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working')) | 1783 | if (isset($_GET['test_session']) |
1974 | { | 1784 | && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working')) { |
1975 | // Step 2: Check if data in session is correct. | 1785 | // Step 2: Check if data in session is correct. |
1976 | $msg = t( | 1786 | $msg = t( |
1977 | '<pre>Sessions do not seem to work correctly on your server.<br>'. | 1787 | '<pre>Sessions do not seem to work correctly on your server.<br>'. |
@@ -1987,19 +1797,18 @@ function install($conf, $sessionManager) { | |||
1987 | echo '<br><a href="?">'. t('Click to try again.') .'</a></pre>'; | 1797 | echo '<br><a href="?">'. t('Click to try again.') .'</a></pre>'; |
1988 | die; | 1798 | die; |
1989 | } | 1799 | } |
1990 | if (!isset($_SESSION['session_tested'])) | 1800 | if (!isset($_SESSION['session_tested'])) { |
1991 | { // Step 1 : Try to store data in session and reload page. | 1801 | // Step 1 : Try to store data in session and reload page. |
1992 | $_SESSION['session_tested'] = 'Working'; // Try to set a variable in session. | 1802 | $_SESSION['session_tested'] = 'Working'; // Try to set a variable in session. |
1993 | header('Location: '.index_url($_SERVER).'?test_session'); // Redirect to check stored data. | 1803 | header('Location: '.index_url($_SERVER).'?test_session'); // Redirect to check stored data. |
1994 | } | 1804 | } |
1995 | if (isset($_GET['test_session'])) | 1805 | if (isset($_GET['test_session'])) { |
1996 | { // Step 3: Sessions are OK. Remove test parameter from URL. | 1806 | // Step 3: Sessions are OK. Remove test parameter from URL. |
1997 | header('Location: '.index_url($_SERVER)); | 1807 | header('Location: '.index_url($_SERVER)); |
1998 | } | 1808 | } |
1999 | 1809 | ||
2000 | 1810 | ||
2001 | if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) | 1811 | if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) { |
2002 | { | ||
2003 | $tz = 'UTC'; | 1812 | $tz = 'UTC'; |
2004 | if (!empty($_POST['continent']) && !empty($_POST['city']) | 1813 | if (!empty($_POST['continent']) && !empty($_POST['city']) |
2005 | && isTimeZoneValid($_POST['continent'], $_POST['city']) | 1814 | && isTimeZoneValid($_POST['continent'], $_POST['city']) |
@@ -2029,23 +1838,25 @@ function install($conf, $sessionManager) { | |||
2029 | ); | 1838 | ); |
2030 | try { | 1839 | try { |
2031 | // Everything is ok, let's create config file. | 1840 | // Everything is ok, let's create config file. |
2032 | $conf->write(isLoggedIn()); | 1841 | $conf->write($loginManager->isLoggedIn()); |
2033 | } | 1842 | } catch (Exception $e) { |
2034 | catch(Exception $e) { | ||
2035 | error_log( | 1843 | error_log( |
2036 | 'ERROR while writing config file after installation.' . PHP_EOL . | 1844 | 'ERROR while writing config file after installation.' . PHP_EOL . |
2037 | $e->getMessage() | 1845 | $e->getMessage() |
2038 | ); | 1846 | ); |
2039 | 1847 | ||
2040 | // TODO: do not handle exceptions/errors in JS. | 1848 | // TODO: do not handle exceptions/errors in JS. |
2041 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?\';</script>'; | 1849 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?\';</script>'; |
2042 | exit; | 1850 | exit; |
2043 | } | 1851 | } |
2044 | echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>'; | 1852 | echo '<script>alert(' |
1853 | .'"Shaarli is now configured. ' | ||
1854 | .'Please enter your login/password and start shaaring your links!"' | ||
1855 | .');document.location=\'?do=login\';</script>'; | ||
2045 | exit; | 1856 | exit; |
2046 | } | 1857 | } |
2047 | 1858 | ||
2048 | $PAGE = new PageBuilder($conf, null, $sessionManager->generateToken()); | 1859 | $PAGE = new PageBuilder($conf, $_SESSION, null, $sessionManager->generateToken()); |
2049 | list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); | 1860 | list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); |
2050 | $PAGE->assign('continents', $continents); | 1861 | $PAGE->assign('continents', $continents); |
2051 | $PAGE->assign('cities', $cities); | 1862 | $PAGE->assign('cities', $cities); |
@@ -2054,246 +1865,24 @@ function install($conf, $sessionManager) { | |||
2054 | exit; | 1865 | exit; |
2055 | } | 1866 | } |
2056 | 1867 | ||
2057 | /** | 1868 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { |
2058 | * Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, | 1869 | showDailyRSS($conf, $loginManager); |
2059 | * I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. | 1870 | exit; |
2060 | * The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail. | ||
2061 | * This function is called by passing the URL: | ||
2062 | * http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] | ||
2063 | * [URL] is the URL of the link (e.g. a flickr page) | ||
2064 | * [HMAC] is the signature for the [URL] (so that these URL cannot be forged). | ||
2065 | * The function below will fetch the image from the webservice and store it in the cache. | ||
2066 | * | ||
2067 | * @param ConfigManager $conf Configuration Manager instance, | ||
2068 | */ | ||
2069 | function genThumbnail($conf) | ||
2070 | { | ||
2071 | // Make sure the parameters in the URL were generated by us. | ||
2072 | $sign = hash_hmac('sha256', $_GET['url'], $conf->get('credentials.salt')); | ||
2073 | if ($sign!=$_GET['hmac']) die('Naughty boy!'); | ||
2074 | |||
2075 | $cacheDir = $conf->get('resource.thumbnails_cache', 'cache'); | ||
2076 | // Let's see if we don't already have the image for this URL in the cache. | ||
2077 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; | ||
2078 | if (is_file($cacheDir .'/'. $thumbname)) | ||
2079 | { // We have the thumbnail, just serve it: | ||
2080 | header('Content-Type: image/jpeg'); | ||
2081 | echo file_get_contents($cacheDir .'/'. $thumbname); | ||
2082 | return; | ||
2083 | } | ||
2084 | // We may also serve a blank image (if service did not respond) | ||
2085 | $blankname=hash('sha1',$_GET['url']).'.gif'; | ||
2086 | if (is_file($cacheDir .'/'. $blankname)) | ||
2087 | { | ||
2088 | header('Content-Type: image/gif'); | ||
2089 | echo file_get_contents($cacheDir .'/'. $blankname); | ||
2090 | return; | ||
2091 | } | ||
2092 | |||
2093 | // Otherwise, generate the thumbnail. | ||
2094 | $url = $_GET['url']; | ||
2095 | $domain = parse_url($url,PHP_URL_HOST); | ||
2096 | |||
2097 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')) | ||
2098 | { | ||
2099 | // Crude replacement to handle new flickr domain policy (They prefer www. now) | ||
2100 | $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url); | ||
2101 | |||
2102 | // Is this a link to an image, or to a flickr page ? | ||
2103 | $imageurl=''; | ||
2104 | if (endsWith(parse_url($url, PHP_URL_PATH), '.jpg')) | ||
2105 | { // This is a direct link to an image. e.g. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg | ||
2106 | preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); | ||
2107 | if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; | ||
2108 | } | ||
2109 | else // This is a flickr page (html) | ||
2110 | { | ||
2111 | // Get the flickr html page. | ||
2112 | list($headers, $content) = get_http_response($url, 20); | ||
2113 | if (strpos($headers[0], '200 OK') !== false) | ||
2114 | { | ||
2115 | // flickr now nicely provides the URL of the thumbnail in each flickr page. | ||
2116 | preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!', $content, $matches); | ||
2117 | if (!empty($matches[1])) $imageurl=$matches[1]; | ||
2118 | |||
2119 | // In albums (and some other pages), the link rel="image_src" is not provided, | ||
2120 | // but flickr provides: | ||
2121 | // <meta property="og:image" content="http://farm4.staticflickr.com/3398/3239339068_25d13535ff_z.jpg" /> | ||
2122 | if ($imageurl=='') | ||
2123 | { | ||
2124 | preg_match('!<meta property=\"og:image\" content=\"(.+?)\"!', $content, $matches); | ||
2125 | if (!empty($matches[1])) $imageurl=$matches[1]; | ||
2126 | } | ||
2127 | } | ||
2128 | } | ||
2129 | |||
2130 | if ($imageurl!='') | ||
2131 | { // Let's download the image. | ||
2132 | // Image is 240x120, so 10 seconds to download should be enough. | ||
2133 | list($headers, $content) = get_http_response($imageurl, 10); | ||
2134 | if (strpos($headers[0], '200 OK') !== false) { | ||
2135 | // Save image to cache. | ||
2136 | file_put_contents($cacheDir .'/'. $thumbname, $content); | ||
2137 | header('Content-Type: image/jpeg'); | ||
2138 | echo $content; | ||
2139 | return; | ||
2140 | } | ||
2141 | } | ||
2142 | } | ||
2143 | |||
2144 | elseif ($domain=='vimeo.com' ) | ||
2145 | { | ||
2146 | // This is more complex: we have to perform a HTTP request, then parse the result. | ||
2147 | // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098 | ||
2148 | $vid = substr(parse_url($url,PHP_URL_PATH),1); | ||
2149 | list($headers, $content) = get_http_response('https://vimeo.com/api/v2/video/'.escape($vid).'.php', 5); | ||
2150 | if (strpos($headers[0], '200 OK') !== false) { | ||
2151 | $t = unserialize($content); | ||
2152 | $imageurl = $t[0]['thumbnail_medium']; | ||
2153 | // Then we download the image and serve it to our client. | ||
2154 | list($headers, $content) = get_http_response($imageurl, 10); | ||
2155 | if (strpos($headers[0], '200 OK') !== false) { | ||
2156 | // Save image to cache. | ||
2157 | file_put_contents($cacheDir .'/'. $thumbname, $content); | ||
2158 | header('Content-Type: image/jpeg'); | ||
2159 | echo $content; | ||
2160 | return; | ||
2161 | } | ||
2162 | } | ||
2163 | } | ||
2164 | |||
2165 | elseif ($domain=='ted.com' || endsWith($domain,'.ted.com')) | ||
2166 | { | ||
2167 | // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page | ||
2168 | // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html | ||
2169 | // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" /> | ||
2170 | list($headers, $content) = get_http_response($url, 5); | ||
2171 | if (strpos($headers[0], '200 OK') !== false) { | ||
2172 | // Extract the link to the thumbnail | ||
2173 | preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!', $content, $matches); | ||
2174 | if (!empty($matches[1])) | ||
2175 | { // Let's download the image. | ||
2176 | $imageurl=$matches[1]; | ||
2177 | // No control on image size, so wait long enough | ||
2178 | list($headers, $content) = get_http_response($imageurl, 20); | ||
2179 | if (strpos($headers[0], '200 OK') !== false) { | ||
2180 | $filepath = $cacheDir .'/'. $thumbname; | ||
2181 | file_put_contents($filepath, $content); // Save image to cache. | ||
2182 | if (resizeImage($filepath)) | ||
2183 | { | ||
2184 | header('Content-Type: image/jpeg'); | ||
2185 | echo file_get_contents($filepath); | ||
2186 | return; | ||
2187 | } | ||
2188 | } | ||
2189 | } | ||
2190 | } | ||
2191 | } | ||
2192 | |||
2193 | elseif ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) | ||
2194 | { | ||
2195 | // There is no thumbnail available for xkcd comics, so download the whole image and resize it. | ||
2196 | // http://xkcd.com/327/ | ||
2197 | // <img src="http://imgs.xkcd.com/comics/exploits_of_a_mom.png" title="<BLABLA>" alt="<BLABLA>" /> | ||
2198 | list($headers, $content) = get_http_response($url, 5); | ||
2199 | if (strpos($headers[0], '200 OK') !== false) { | ||
2200 | // Extract the link to the thumbnail | ||
2201 | preg_match('!<img src="(http://imgs.xkcd.com/comics/.*)" title="[^s]!', $content, $matches); | ||
2202 | if (!empty($matches[1])) | ||
2203 | { // Let's download the image. | ||
2204 | $imageurl=$matches[1]; | ||
2205 | // No control on image size, so wait long enough | ||
2206 | list($headers, $content) = get_http_response($imageurl, 20); | ||
2207 | if (strpos($headers[0], '200 OK') !== false) { | ||
2208 | $filepath = $cacheDir.'/'.$thumbname; | ||
2209 | // Save image to cache. | ||
2210 | file_put_contents($filepath, $content); | ||
2211 | if (resizeImage($filepath)) | ||
2212 | { | ||
2213 | header('Content-Type: image/jpeg'); | ||
2214 | echo file_get_contents($filepath); | ||
2215 | return; | ||
2216 | } | ||
2217 | } | ||
2218 | } | ||
2219 | } | ||
2220 | } | ||
2221 | |||
2222 | else | ||
2223 | { | ||
2224 | // For all other domains, we try to download the image and make a thumbnail. | ||
2225 | // We allow 30 seconds max to download (and downloads are limited to 4 Mb) | ||
2226 | list($headers, $content) = get_http_response($url, 30); | ||
2227 | if (strpos($headers[0], '200 OK') !== false) { | ||
2228 | $filepath = $cacheDir .'/'.$thumbname; | ||
2229 | // Save image to cache. | ||
2230 | file_put_contents($filepath, $content); | ||
2231 | if (resizeImage($filepath)) | ||
2232 | { | ||
2233 | header('Content-Type: image/jpeg'); | ||
2234 | echo file_get_contents($filepath); | ||
2235 | return; | ||
2236 | } | ||
2237 | } | ||
2238 | } | ||
2239 | |||
2240 | |||
2241 | // Otherwise, return an empty image (8x8 transparent gif) | ||
2242 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); | ||
2243 | // Also put something in cache so that this URL is not requested twice. | ||
2244 | file_put_contents($cacheDir .'/'. $blankname, $blankgif); | ||
2245 | header('Content-Type: image/gif'); | ||
2246 | echo $blankgif; | ||
2247 | } | ||
2248 | |||
2249 | // Make a thumbnail of the image (to width: 120 pixels) | ||
2250 | // Returns true if success, false otherwise. | ||
2251 | function resizeImage($filepath) | ||
2252 | { | ||
2253 | if (!function_exists('imagecreatefromjpeg')) return false; // GD not present: no thumbnail possible. | ||
2254 | |||
2255 | // Trick: some stupid people rename GIF as JPEG... or else. | ||
2256 | // So we really try to open each image type whatever the extension is. | ||
2257 | $header=file_get_contents($filepath,false,NULL,0,256); // Read first 256 bytes and try to sniff file type. | ||
2258 | $im=false; | ||
2259 | $i=strpos($header,'GIF8'); if (($i!==false) && ($i==0)) $im = imagecreatefromgif($filepath); // Well this is crude, but it should be enough. | ||
2260 | $i=strpos($header,'PNG'); if (($i!==false) && ($i==1)) $im = imagecreatefrompng($filepath); | ||
2261 | $i=strpos($header,'JFIF'); if ($i!==false) $im = imagecreatefromjpeg($filepath); | ||
2262 | if (!$im) return false; // Unable to open image (corrupted or not an image) | ||
2263 | $w = imagesx($im); | ||
2264 | $h = imagesy($im); | ||
2265 | $ystart = 0; $yheight=$h; | ||
2266 | if ($h>$w) { $ystart= ($h/2)-($w/2); $yheight=$w/2; } | ||
2267 | $nw = 120; // Desired width | ||
2268 | $nh = min(floor(($h*$nw)/$w),120); // Compute new width/height, but maximum 120 pixels height. | ||
2269 | // Resize image: | ||
2270 | $im2 = imagecreatetruecolor($nw,$nh); | ||
2271 | imagecopyresampled($im2, $im, 0, 0, 0, $ystart, $nw, $nh, $w, $yheight); | ||
2272 | imageinterlace($im2,true); // For progressive JPEG. | ||
2273 | $tempname=$filepath.'_TEMP.jpg'; | ||
2274 | imagejpeg($im2, $tempname, 90); | ||
2275 | imagedestroy($im); | ||
2276 | imagedestroy($im2); | ||
2277 | unlink($filepath); | ||
2278 | rename($tempname,$filepath); // Overwrite original picture with thumbnail. | ||
2279 | return true; | ||
2280 | } | 1871 | } |
2281 | 1872 | ||
2282 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail($conf); exit; } // Thumbnail generation/cache does not need the link database. | ||
2283 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS($conf); exit; } | ||
2284 | if (!isset($_SESSION['LINKS_PER_PAGE'])) { | 1873 | if (!isset($_SESSION['LINKS_PER_PAGE'])) { |
2285 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); | 1874 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); |
2286 | } | 1875 | } |
2287 | 1876 | ||
2288 | try { | 1877 | try { |
2289 | $history = new History($conf->get('resource.history')); | 1878 | $history = new History($conf->get('resource.history')); |
2290 | } catch(Exception $e) { | 1879 | } catch (Exception $e) { |
2291 | die($e->getMessage()); | 1880 | die($e->getMessage()); |
2292 | } | 1881 | } |
2293 | 1882 | ||
2294 | $linkDb = new LinkDB( | 1883 | $linkDb = new LinkDB( |
2295 | $conf->get('resource.datastore'), | 1884 | $conf->get('resource.datastore'), |
2296 | isLoggedIn(), | 1885 | $loginManager->isLoggedIn(), |
2297 | $conf->get('privacy.hide_public_links'), | 1886 | $conf->get('privacy.hide_public_links'), |
2298 | $conf->get('redirector.url'), | 1887 | $conf->get('redirector.url'), |
2299 | $conf->get('redirector.encode_url') | 1888 | $conf->get('redirector.encode_url') |
@@ -2306,23 +1895,37 @@ $container['history'] = $history; | |||
2306 | $app = new \Slim\App($container); | 1895 | $app = new \Slim\App($container); |
2307 | 1896 | ||
2308 | // REST API routes | 1897 | // REST API routes |
2309 | $app->group('/api/v1', function() { | 1898 | $app->group('/api/v1', function () { |
2310 | $this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo')->setName('getInfo'); | 1899 | $this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo')->setName('getInfo'); |
2311 | $this->get('/links', '\Shaarli\Api\Controllers\Links:getLinks')->setName('getLinks'); | 1900 | $this->get('/links', '\Shaarli\Api\Controllers\Links:getLinks')->setName('getLinks'); |
2312 | $this->get('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:getLink')->setName('getLink'); | 1901 | $this->get('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:getLink')->setName('getLink'); |
2313 | $this->post('/links', '\Shaarli\Api\Controllers\Links:postLink')->setName('postLink'); | 1902 | $this->post('/links', '\Shaarli\Api\Controllers\Links:postLink')->setName('postLink'); |
2314 | $this->put('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:putLink')->setName('putLink'); | 1903 | $this->put('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:putLink')->setName('putLink'); |
2315 | $this->delete('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:deleteLink')->setName('deleteLink'); | 1904 | $this->delete('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:deleteLink')->setName('deleteLink'); |
1905 | |||
1906 | $this->get('/tags', '\Shaarli\Api\Controllers\Tags:getTags')->setName('getTags'); | ||
1907 | $this->get('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:getTag')->setName('getTag'); | ||
1908 | $this->put('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:putTag')->setName('putTag'); | ||
1909 | $this->delete('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:deleteTag')->setName('deleteTag'); | ||
1910 | |||
2316 | $this->get('/history', '\Shaarli\Api\Controllers\History:getHistory')->setName('getHistory'); | 1911 | $this->get('/history', '\Shaarli\Api\Controllers\History:getHistory')->setName('getHistory'); |
2317 | })->add('\Shaarli\Api\ApiMiddleware'); | 1912 | })->add('\Shaarli\Api\ApiMiddleware'); |
2318 | 1913 | ||
2319 | $response = $app->run(true); | 1914 | $response = $app->run(true); |
1915 | |||
2320 | // Hack to make Slim and Shaarli router work together: | 1916 | // Hack to make Slim and Shaarli router work together: |
2321 | // If a Slim route isn't found and NOT API call, we call renderPage(). | 1917 | // If a Slim route isn't found and NOT API call, we call renderPage(). |
2322 | if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], '/api/v1') === false) { | 1918 | if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], '/api/v1') === false) { |
2323 | // We use UTF-8 for proper international characters handling. | 1919 | // We use UTF-8 for proper international characters handling. |
2324 | header('Content-Type: text/html; charset=utf-8'); | 1920 | header('Content-Type: text/html; charset=utf-8'); |
2325 | renderPage($conf, $pluginManager, $linkDb, $history, $sessionManager); | 1921 | renderPage($conf, $pluginManager, $linkDb, $history, $sessionManager, $loginManager); |
2326 | } else { | 1922 | } else { |
1923 | $response = $response | ||
1924 | ->withHeader('Access-Control-Allow-Origin', '*') | ||
1925 | ->withHeader( | ||
1926 | 'Access-Control-Allow-Headers', | ||
1927 | 'X-Requested-With, Content-Type, Accept, Origin, Authorization' | ||
1928 | ) | ||
1929 | ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); | ||
2327 | $app->respond($response); | 1930 | $app->respond($response); |
2328 | } | 1931 | } |