aboutsummaryrefslogtreecommitdiffhomepage
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/Utils.php4
-rw-r--r--application/api/ApiMiddleware.php10
-rw-r--r--application/api/ApiUtils.php11
-rw-r--r--application/api/controllers/ApiController.php3
-rw-r--r--application/api/controllers/Links.php4
-rw-r--r--application/bookmark/BookmarkFileService.php4
-rw-r--r--application/bookmark/BookmarkFilter.php17
-rw-r--r--application/bookmark/BookmarkInitializer.php74
-rw-r--r--application/bookmark/LinkUtils.php2
-rw-r--r--application/config/ConfigJson.php2
-rw-r--r--application/container/ContainerBuilder.php4
-rw-r--r--application/container/ShaarliContainer.php9
-rw-r--r--application/feed/FeedBuilder.php6
-rw-r--r--application/formatter/BookmarkFormatter.php26
-rw-r--r--application/formatter/BookmarkMarkdownExtraFormatter.php24
-rw-r--r--application/front/controller/admin/ConfigureController.php2
-rw-r--r--application/front/controller/admin/ManageShaareController.php16
-rw-r--r--application/front/controller/admin/ManageTagController.php4
-rw-r--r--application/front/controller/admin/PluginsController.php1
-rw-r--r--application/front/controller/admin/ShaarliAdminController.php2
-rw-r--r--application/front/controller/visitor/BookmarkListController.php7
-rw-r--r--application/front/controller/visitor/DailyController.php2
-rw-r--r--application/front/controller/visitor/ErrorNotFoundController.php29
-rw-r--r--application/front/controller/visitor/FeedController.php4
-rw-r--r--application/front/controller/visitor/ShaarliVisitorController.php33
-rw-r--r--application/front/controller/visitor/TagCloudController.php12
-rw-r--r--application/http/HttpUtils.php8
-rw-r--r--application/legacy/LegacyController.php12
-rw-r--r--application/legacy/LegacyRouter.php134
-rw-r--r--application/plugin/PluginManager.php25
-rw-r--r--application/render/PageBuilder.php2
31 files changed, 282 insertions, 211 deletions
diff --git a/application/Utils.php b/application/Utils.php
index 9c9eaaa2..bcfda65c 100644
--- a/application/Utils.php
+++ b/application/Utils.php
@@ -95,14 +95,14 @@ function escape($input)
95 return null; 95 return null;
96 } 96 }
97 97
98 if (is_bool($input)) { 98 if (is_bool($input) || is_int($input) || is_float($input) || $input instanceof DateTimeInterface) {
99 return $input; 99 return $input;
100 } 100 }
101 101
102 if (is_array($input)) { 102 if (is_array($input)) {
103 $out = array(); 103 $out = array();
104 foreach ($input as $key => $value) { 104 foreach ($input as $key => $value) {
105 $out[$key] = escape($value); 105 $out[escape($key)] = escape($value);
106 } 106 }
107 return $out; 107 return $out;
108 } 108 }
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index 09ce6445..f5b53b01 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -107,7 +107,9 @@ class ApiMiddleware
107 */ 107 */
108 protected function checkToken($request) 108 protected function checkToken($request)
109 { 109 {
110 if (! $request->hasHeader('Authorization')) { 110 if (!$request->hasHeader('Authorization')
111 && !isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])
112 ) {
111 throw new ApiAuthorizationException('JWT token not provided'); 113 throw new ApiAuthorizationException('JWT token not provided');
112 } 114 }
113 115
@@ -115,7 +117,11 @@ class ApiMiddleware
115 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); 117 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration');
116 } 118 }
117 119
118 $authorization = $request->getHeaderLine('Authorization'); 120 if (isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])) {
121 $authorization = $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'];
122 } else {
123 $authorization = $request->getHeaderLine('Authorization');
124 }
119 125
120 if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { 126 if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) {
121 throw new ApiAuthorizationException('Invalid JWT header'); 127 throw new ApiAuthorizationException('Invalid JWT header');
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php
index faebb8f5..4a6326f0 100644
--- a/application/api/ApiUtils.php
+++ b/application/api/ApiUtils.php
@@ -94,7 +94,7 @@ class ApiUtils
94 * 94 *
95 * @return Bookmark instance. 95 * @return Bookmark instance.
96 */ 96 */
97 public static function buildLinkFromRequest($input, $defaultPrivate) 97 public static function buildBookmarkFromRequest($input, $defaultPrivate): Bookmark
98 { 98 {
99 $bookmark = new Bookmark(); 99 $bookmark = new Bookmark();
100 $url = ! empty($input['url']) ? cleanup_url($input['url']) : ''; 100 $url = ! empty($input['url']) ? cleanup_url($input['url']) : '';
@@ -110,6 +110,15 @@ class ApiUtils
110 $bookmark->setTags(! empty($input['tags']) ? $input['tags'] : []); 110 $bookmark->setTags(! empty($input['tags']) ? $input['tags'] : []);
111 $bookmark->setPrivate($private); 111 $bookmark->setPrivate($private);
112 112
113 $created = \DateTime::createFromFormat(\DateTime::ATOM, $input['created'] ?? '');
114 if ($created instanceof \DateTimeInterface) {
115 $bookmark->setCreated($created);
116 }
117 $updated = \DateTime::createFromFormat(\DateTime::ATOM, $input['updated'] ?? '');
118 if ($updated instanceof \DateTimeInterface) {
119 $bookmark->setUpdated($updated);
120 }
121
113 return $bookmark; 122 return $bookmark;
114 } 123 }
115 124
diff --git a/application/api/controllers/ApiController.php b/application/api/controllers/ApiController.php
index c4b3d0c3..88a845eb 100644
--- a/application/api/controllers/ApiController.php
+++ b/application/api/controllers/ApiController.php
@@ -4,6 +4,7 @@ namespace Shaarli\Api\Controllers;
4 4
5use Shaarli\Bookmark\BookmarkServiceInterface; 5use Shaarli\Bookmark\BookmarkServiceInterface;
6use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
7use Shaarli\History;
7use Slim\Container; 8use Slim\Container;
8 9
9/** 10/**
@@ -31,7 +32,7 @@ abstract class ApiController
31 protected $bookmarkService; 32 protected $bookmarkService;
32 33
33 /** 34 /**
34 * @var HistoryController 35 * @var History
35 */ 36 */
36 protected $history; 37 protected $history;
37 38
diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php
index 29247950..778097fd 100644
--- a/application/api/controllers/Links.php
+++ b/application/api/controllers/Links.php
@@ -116,7 +116,7 @@ class Links extends ApiController
116 public function postLink($request, $response) 116 public function postLink($request, $response)
117 { 117 {
118 $data = $request->getParsedBody(); 118 $data = $request->getParsedBody();
119 $bookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); 119 $bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links'));
120 // duplicate by URL, return 409 Conflict 120 // duplicate by URL, return 409 Conflict
121 if (! empty($bookmark->getUrl()) 121 if (! empty($bookmark->getUrl())
122 && ! empty($dup = $this->bookmarkService->findByUrl($bookmark->getUrl())) 122 && ! empty($dup = $this->bookmarkService->findByUrl($bookmark->getUrl()))
@@ -155,7 +155,7 @@ class Links extends ApiController
155 $index = index_url($this->ci['environment']); 155 $index = index_url($this->ci['environment']);
156 $data = $request->getParsedBody(); 156 $data = $request->getParsedBody();
157 157
158 $requestBookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links')); 158 $requestBookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links'));
159 // duplicate URL on a different link, return 409 Conflict 159 // duplicate URL on a different link, return 409 Conflict
160 if (! empty($requestBookmark->getUrl()) 160 if (! empty($requestBookmark->getUrl())
161 && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl())) 161 && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl()))
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php
index e3a61146..c9ec2609 100644
--- a/application/bookmark/BookmarkFileService.php
+++ b/application/bookmark/BookmarkFileService.php
@@ -362,7 +362,9 @@ class BookmarkFileService implements BookmarkServiceInterface
362 */ 362 */
363 public function filterDay($request) 363 public function filterDay($request)
364 { 364 {
365 return $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_DAY, $request); 365 $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
366
367 return $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_DAY, $request, false, $visibility);
366 } 368 }
367 369
368 /** 370 /**
diff --git a/application/bookmark/BookmarkFilter.php b/application/bookmark/BookmarkFilter.php
index 797a36b8..6636bbfe 100644
--- a/application/bookmark/BookmarkFilter.php
+++ b/application/bookmark/BookmarkFilter.php
@@ -115,7 +115,7 @@ class BookmarkFilter
115 return $this->filterTags($request, $casesensitive, $visibility); 115 return $this->filterTags($request, $casesensitive, $visibility);
116 } 116 }
117 case self::$FILTER_DAY: 117 case self::$FILTER_DAY:
118 return $this->filterDay($request); 118 return $this->filterDay($request, $visibility);
119 default: 119 default:
120 return $this->noFilter($visibility); 120 return $this->noFilter($visibility);
121 } 121 }
@@ -425,21 +425,26 @@ class BookmarkFilter
425 * print_r($mydb->filterDay('20120125')); 425 * print_r($mydb->filterDay('20120125'));
426 * 426 *
427 * @param string $day day to filter. 427 * @param string $day day to filter.
428 * 428 * @param string $visibility return only all/private/public bookmarks.
429
429 * @return array all link matching given day. 430 * @return array all link matching given day.
430 * 431 *
431 * @throws Exception if date format is invalid. 432 * @throws Exception if date format is invalid.
432 */ 433 */
433 public function filterDay($day) 434 public function filterDay($day, $visibility)
434 { 435 {
435 if (!checkDateFormat('Ymd', $day)) { 436 if (!checkDateFormat('Ymd', $day)) {
436 throw new Exception('Invalid date format'); 437 throw new Exception('Invalid date format');
437 } 438 }
438 439
439 $filtered = []; 440 $filtered = [];
440 foreach ($this->bookmarks as $key => $l) { 441 foreach ($this->bookmarks as $key => $bookmark) {
441 if ($l->getCreated()->format('Ymd') == $day) { 442 if ($visibility === static::$PUBLIC && $bookmark->isPrivate()) {
442 $filtered[$key] = $l; 443 continue;
444 }
445
446 if ($bookmark->getCreated()->format('Ymd') == $day) {
447 $filtered[$key] = $bookmark;
443 } 448 }
444 } 449 }
445 450
diff --git a/application/bookmark/BookmarkInitializer.php b/application/bookmark/BookmarkInitializer.php
index cd2d1724..815047e3 100644
--- a/application/bookmark/BookmarkInitializer.php
+++ b/application/bookmark/BookmarkInitializer.php
@@ -34,25 +34,77 @@ class BookmarkInitializer
34 public function initialize() 34 public function initialize()
35 { 35 {
36 $bookmark = new Bookmark(); 36 $bookmark = new Bookmark();
37 $bookmark->setTitle(t('My secret stuff... - Pastebin.com')); 37 $bookmark->setTitle('quicksilver (loop) on Vimeo ' . t('(private bookmark with thumbnail demo)'));
38 $bookmark->setUrl('http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8='); 38 $bookmark->setUrl('https://vimeo.com/153493904');
39 $bookmark->setDescription(t('Shhhh! I\'m a private link only YOU can see. You can delete me too.')); 39 $bookmark->setDescription(t(
40 $bookmark->setTagsString('secretstuff'); 40'Shaarli will automatically pick up the thumbnail for links to a variety of websites.
41
42Explore your new Shaarli instance by trying out controls and menus.
43Visit the project on [Github](https://github.com/shaarli/Shaarli) or [the documentation](https://shaarli.readthedocs.io/en/master/) to learn more about Shaarli.
44
45Now you can edit or delete the default shaares.
46'
47 ));
48 $bookmark->setTagsString('shaarli help thumbnail');
49 $bookmark->setPrivate(true);
50 $this->bookmarkService->add($bookmark, false);
51
52 $bookmark = new Bookmark();
53 $bookmark->setTitle(t('Note: Shaare descriptions'));
54 $bookmark->setDescription(t(
55'Adding a shaare without entering a URL creates a text-only "note" post such as this one.
56This note is private, so you are the only one able to see it while logged in.
57
58You can use this to keep notes, post articles, code snippets, and much more.
59
60The Markdown formatting setting allows you to format your notes and bookmark description:
61
62### Title headings
63
64#### Multiple headings levels
65 * bullet lists
66 * _italic_ text
67 * **bold** text
68 * ~~strike through~~ text
69 * `code` blocks
70 * images
71 * [links](https://en.wikipedia.org/wiki/Markdown)
72
73Markdown also supports tables:
74
75| Name | Type | Color | Qty |
76| ------- | --------- | ------ | ----- |
77| Orange | Fruit | Orange | 126 |
78| Apple | Fruit | Any | 62 |
79| Lemon | Fruit | Yellow | 30 |
80| Carrot | Vegetable | Red | 14 |
81'
82 ));
83 $bookmark->setTagsString('shaarli help');
41 $bookmark->setPrivate(true); 84 $bookmark->setPrivate(true);
42 $this->bookmarkService->add($bookmark, false); 85 $this->bookmarkService->add($bookmark, false);
43 86
44 $bookmark = new Bookmark(); 87 $bookmark = new Bookmark();
45 $bookmark->setTitle(t('The personal, minimalist, super-fast, database free, bookmarking service')); 88 $bookmark->setTitle(
46 $bookmark->setUrl('https://shaarli.readthedocs.io', []); 89 'Shaarli - ' . t('The personal, minimalist, super-fast, database free, bookmarking service')
90 );
47 $bookmark->setDescription(t( 91 $bookmark->setDescription(t(
48 'Welcome to Shaarli! This is your first public bookmark. ' 92'Welcome to Shaarli!
49 . 'To edit or delete me, you must first login. 93
94Shaarli allows you to bookmark your favorite pages, and share them with others or store them privately.
95You can add a description to your bookmarks, such as this one, and tag them.
96
97Create a new shaare by clicking the `+Shaare` button, or using any of the recommended tools (browser extension, mobile app, bookmarklet, REST API, etc.).
50 98
51To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page. 99You can easily retrieve your links, even with thousands of them, using the internal search engine, or search through tags (e.g. this Shaare is tagged with `shaarli` and `help`).
100Hashtags such as #shaarli #help are also supported.
101You can also filter the available [RSS feed](/feed/atom) and picture wall by tag or plaintext search.
52 102
53You use the community supported version of the original Shaarli project, by Sebastien Sauvage.' 103We hope that you will enjoy using Shaarli, maintained with ❤️ by the community!
104Feel free to open [an issue](https://github.com/shaarli/Shaarli/issues) if you have a suggestion or encounter an issue.
105'
54 )); 106 ));
55 $bookmark->setTagsString('opensource software'); 107 $bookmark->setTagsString('shaarli help');
56 $this->bookmarkService->add($bookmark, false); 108 $this->bookmarkService->add($bookmark, false);
57 } 109 }
58} 110}
diff --git a/application/bookmark/LinkUtils.php b/application/bookmark/LinkUtils.php
index 03e1b82a..faf5dbfd 100644
--- a/application/bookmark/LinkUtils.php
+++ b/application/bookmark/LinkUtils.php
@@ -26,7 +26,7 @@ function html_extract_title($html)
26 */ 26 */
27function header_extract_charset($header) 27function header_extract_charset($header)
28{ 28{
29 preg_match('/charset="?([^; ]+)/i', $header, $match); 29 preg_match('/charset=["\']?([^; "\']+)/i', $header, $match);
30 if (! empty($match[1])) { 30 if (! empty($match[1])) {
31 return strtolower(trim($match[1])); 31 return strtolower(trim($match[1]));
32 } 32 }
diff --git a/application/config/ConfigJson.php b/application/config/ConfigJson.php
index 4509357c..c0c0dab9 100644
--- a/application/config/ConfigJson.php
+++ b/application/config/ConfigJson.php
@@ -46,7 +46,7 @@ class ConfigJson implements ConfigIO
46 // JSON_PRETTY_PRINT is available from PHP 5.4. 46 // JSON_PRETTY_PRINT is available from PHP 5.4.
47 $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0; 47 $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
48 $data = self::getPhpHeaders() . json_encode($conf, $print) . self::getPhpSuffix(); 48 $data = self::getPhpHeaders() . json_encode($conf, $print) . self::getPhpSuffix();
49 if (!file_put_contents($filepath, $data)) { 49 if (empty($filepath) || !file_put_contents($filepath, $data)) {
50 throw new \Shaarli\Exceptions\IOException( 50 throw new \Shaarli\Exceptions\IOException(
51 $filepath, 51 $filepath,
52 t('Shaarli could not create the config file. '. 52 t('Shaarli could not create the config file. '.
diff --git a/application/container/ContainerBuilder.php b/application/container/ContainerBuilder.php
index 58067c99..55bb51b5 100644
--- a/application/container/ContainerBuilder.php
+++ b/application/container/ContainerBuilder.php
@@ -10,6 +10,7 @@ use Shaarli\Config\ConfigManager;
10use Shaarli\Feed\FeedBuilder; 10use Shaarli\Feed\FeedBuilder;
11use Shaarli\Formatter\FormatterFactory; 11use Shaarli\Formatter\FormatterFactory;
12use Shaarli\Front\Controller\Visitor\ErrorController; 12use Shaarli\Front\Controller\Visitor\ErrorController;
13use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
13use Shaarli\History; 14use Shaarli\History;
14use Shaarli\Http\HttpAccess; 15use Shaarli\Http\HttpAccess;
15use Shaarli\Netscape\NetscapeBookmarkUtils; 16use Shaarli\Netscape\NetscapeBookmarkUtils;
@@ -149,6 +150,9 @@ class ContainerBuilder
149 ); 150 );
150 }; 151 };
151 152
153 $container['notFoundHandler'] = function (ShaarliContainer $container): ErrorNotFoundController {
154 return new ErrorNotFoundController($container);
155 };
152 $container['errorHandler'] = function (ShaarliContainer $container): ErrorController { 156 $container['errorHandler'] = function (ShaarliContainer $container): ErrorController {
153 return new ErrorController($container); 157 return new ErrorController($container);
154 }; 158 };
diff --git a/application/container/ShaarliContainer.php b/application/container/ShaarliContainer.php
index 9a9a974a..66e669aa 100644
--- a/application/container/ShaarliContainer.php
+++ b/application/container/ShaarliContainer.php
@@ -24,21 +24,22 @@ use Slim\Container;
24/** 24/**
25 * Extension of Slim container to document the injected objects. 25 * Extension of Slim container to document the injected objects.
26 * 26 *
27 * @property string $basePath Shaarli's instance base path (e.g. `/shaarli/`) 27 * @property string $basePath Shaarli's instance base path (e.g. `/shaarli/`)
28 * @property BookmarkServiceInterface $bookmarkService 28 * @property BookmarkServiceInterface $bookmarkService
29 * @property CookieManager $cookieManager 29 * @property CookieManager $cookieManager
30 * @property ConfigManager $conf 30 * @property ConfigManager $conf
31 * @property mixed[] $environment $_SERVER automatically injected by Slim 31 * @property mixed[] $environment $_SERVER automatically injected by Slim
32 * @property callable $errorHandler Overrides default Slim exception display 32 * @property callable $errorHandler Overrides default Slim exception display
33 * @property FeedBuilder $feedBuilder 33 * @property FeedBuilder $feedBuilder
34 * @property FormatterFactory $formatterFactory 34 * @property FormatterFactory $formatterFactory
35 * @property History $history 35 * @property History $history
36 * @property HttpAccess $httpAccess 36 * @property HttpAccess $httpAccess
37 * @property LoginManager $loginManager 37 * @property LoginManager $loginManager
38 * @property NetscapeBookmarkUtils $netscapeBookmarkUtils 38 * @property NetscapeBookmarkUtils $netscapeBookmarkUtils
39 * @property callable $notFoundHandler Overrides default Slim exception display
39 * @property PageBuilder $pageBuilder 40 * @property PageBuilder $pageBuilder
40 * @property PageCacheManager $pageCacheManager 41 * @property PageCacheManager $pageCacheManager
41 * @property callable $phpErrorHandler Overrides default Slim PHP error display 42 * @property callable $phpErrorHandler Overrides default Slim PHP error display
42 * @property PluginManager $pluginManager 43 * @property PluginManager $pluginManager
43 * @property SessionManager $sessionManager 44 * @property SessionManager $sessionManager
44 * @property Thumbnailer $thumbnailer 45 * @property Thumbnailer $thumbnailer
diff --git a/application/feed/FeedBuilder.php b/application/feed/FeedBuilder.php
index 3653c32f..f6def630 100644
--- a/application/feed/FeedBuilder.php
+++ b/application/feed/FeedBuilder.php
@@ -122,9 +122,9 @@ class FeedBuilder
122 $data['language'] = $this->getTypeLanguage($feedType); 122 $data['language'] = $this->getTypeLanguage($feedType);
123 $data['last_update'] = $this->getLatestDateFormatted($feedType); 123 $data['last_update'] = $this->getLatestDateFormatted($feedType);
124 $data['show_dates'] = !$this->hideDates || $this->isLoggedIn; 124 $data['show_dates'] = !$this->hideDates || $this->isLoggedIn;
125 // Remove leading slash from REQUEST_URI. 125 // Remove leading path from REQUEST_URI (already contained in $pageaddr).
126 $data['self_link'] = escape(server_url($this->serverInfo)) 126 $requestUri = preg_replace('#(.*?/)(feed.*)#', '$2', escape($this->serverInfo['REQUEST_URI']));
127 . escape($this->serverInfo['REQUEST_URI']); 127 $data['self_link'] = $pageaddr . $requestUri;
128 $data['index_url'] = $pageaddr; 128 $data['index_url'] = $pageaddr;
129 $data['usepermalinks'] = $this->usePermalinks === true; 129 $data['usepermalinks'] = $this->usePermalinks === true;
130 $data['links'] = $linkDisplayed; 130 $data['links'] = $linkDisplayed;
diff --git a/application/formatter/BookmarkFormatter.php b/application/formatter/BookmarkFormatter.php
index 22ba7aae..0042dafe 100644
--- a/application/formatter/BookmarkFormatter.php
+++ b/application/formatter/BookmarkFormatter.php
@@ -58,7 +58,9 @@ abstract class BookmarkFormatter
58 $out['title'] = $this->formatTitle($bookmark); 58 $out['title'] = $this->formatTitle($bookmark);
59 $out['description'] = $this->formatDescription($bookmark); 59 $out['description'] = $this->formatDescription($bookmark);
60 $out['thumbnail'] = $this->formatThumbnail($bookmark); 60 $out['thumbnail'] = $this->formatThumbnail($bookmark);
61 $out['urlencoded_taglist'] = $this->formatUrlEncodedTagList($bookmark);
61 $out['taglist'] = $this->formatTagList($bookmark); 62 $out['taglist'] = $this->formatTagList($bookmark);
63 $out['urlencoded_tags'] = $this->formatUrlEncodedTagString($bookmark);
62 $out['tags'] = $this->formatTagString($bookmark); 64 $out['tags'] = $this->formatTagString($bookmark);
63 $out['sticky'] = $bookmark->isSticky(); 65 $out['sticky'] = $bookmark->isSticky();
64 $out['private'] = $bookmark->isPrivate(); 66 $out['private'] = $bookmark->isPrivate();
@@ -182,6 +184,18 @@ abstract class BookmarkFormatter
182 } 184 }
183 185
184 /** 186 /**
187 * Format Url Encoded Tags
188 *
189 * @param Bookmark $bookmark instance
190 *
191 * @return array formatted Tags
192 */
193 protected function formatUrlEncodedTagList($bookmark)
194 {
195 return array_map('urlencode', $this->filterTagList($bookmark->getTags()));
196 }
197
198 /**
185 * Format TagString 199 * Format TagString
186 * 200 *
187 * @param Bookmark $bookmark instance 201 * @param Bookmark $bookmark instance
@@ -194,6 +208,18 @@ abstract class BookmarkFormatter
194 } 208 }
195 209
196 /** 210 /**
211 * Format TagString
212 *
213 * @param Bookmark $bookmark instance
214 *
215 * @return string formatted TagString
216 */
217 protected function formatUrlEncodedTagString($bookmark)
218 {
219 return implode(' ', $this->formatUrlEncodedTagList($bookmark));
220 }
221
222 /**
197 * Format Class 223 * Format Class
198 * Used to add specific CSS class for a link 224 * Used to add specific CSS class for a link
199 * 225 *
diff --git a/application/formatter/BookmarkMarkdownExtraFormatter.php b/application/formatter/BookmarkMarkdownExtraFormatter.php
new file mode 100644
index 00000000..0694b23f
--- /dev/null
+++ b/application/formatter/BookmarkMarkdownExtraFormatter.php
@@ -0,0 +1,24 @@
1<?php
2
3namespace Shaarli\Formatter;
4
5use Shaarli\Config\ConfigManager;
6
7/**
8 * Class BookmarkMarkdownExtraFormatter
9 *
10 * Format bookmark description into MarkdownExtra format.
11 *
12 * @see https://michelf.ca/projects/php-markdown/extra/
13 *
14 * @package Shaarli\Formatter
15 */
16class BookmarkMarkdownExtraFormatter extends BookmarkMarkdownFormatter
17{
18 public function __construct(ConfigManager $conf, bool $isLoggedIn)
19 {
20 parent::__construct($conf, $isLoggedIn);
21
22 $this->parsedown = new \ParsedownExtra();
23 }
24}
diff --git a/application/front/controller/admin/ConfigureController.php b/application/front/controller/admin/ConfigureController.php
index e675fcca..0ed7ad81 100644
--- a/application/front/controller/admin/ConfigureController.php
+++ b/application/front/controller/admin/ConfigureController.php
@@ -30,7 +30,7 @@ class ConfigureController extends ShaarliAdminController
30 'theme_available', 30 'theme_available',
31 ThemeUtils::getThemes($this->container->conf->get('resource.raintpl_tpl')) 31 ThemeUtils::getThemes($this->container->conf->get('resource.raintpl_tpl'))
32 ); 32 );
33 $this->assignView('formatter_available', ['default', 'markdown']); 33 $this->assignView('formatter_available', ['default', 'markdown', 'markdownExtra']);
34 list($continents, $cities) = generateTimeZoneData( 34 list($continents, $cities) = generateTimeZoneData(
35 timezone_identifiers_list(), 35 timezone_identifiers_list(),
36 $this->container->conf->get('general.timezone') 36 $this->container->conf->get('general.timezone')
diff --git a/application/front/controller/admin/ManageShaareController.php b/application/front/controller/admin/ManageShaareController.php
index 33e1188e..bb083486 100644
--- a/application/front/controller/admin/ManageShaareController.php
+++ b/application/front/controller/admin/ManageShaareController.php
@@ -69,7 +69,7 @@ class ManageShaareController extends ShaarliAdminController
69 $retrieveDescription 69 $retrieveDescription
70 ) 70 )
71 ); 71 );
72 if (! empty($title) && strtolower($charset) !== 'utf-8') { 72 if (! empty($title) && strtolower($charset) !== 'utf-8' && mb_check_encoding($charset)) {
73 $title = mb_convert_encoding($title, 'utf-8', $charset); 73 $title = mb_convert_encoding($title, 'utf-8', $charset);
74 } 74 }
75 } 75 }
@@ -78,13 +78,13 @@ class ManageShaareController extends ShaarliAdminController
78 $title = $this->container->conf->get('general.default_note_title', t('Note: ')); 78 $title = $this->container->conf->get('general.default_note_title', t('Note: '));
79 } 79 }
80 80
81 $link = escape([ 81 $link = [
82 'title' => $title, 82 'title' => $title,
83 'url' => $url ?? '', 83 'url' => $url ?? '',
84 'description' => $description ?? '', 84 'description' => $description ?? '',
85 'tags' => $tags ?? '', 85 'tags' => $tags ?? '',
86 'private' => $private, 86 'private' => $private,
87 ]); 87 ];
88 } else { 88 } else {
89 $formatter = $this->container->formatterFactory->getFormatter('raw'); 89 $formatter = $this->container->formatterFactory->getFormatter('raw');
90 $link = $formatter->format($bookmark); 90 $link = $formatter->format($bookmark);
@@ -127,7 +127,7 @@ class ManageShaareController extends ShaarliAdminController
127 $this->checkToken($request); 127 $this->checkToken($request);
128 128
129 // lf_id should only be present if the link exists. 129 // lf_id should only be present if the link exists.
130 $id = $request->getParam('lf_id') ? intval(escape($request->getParam('lf_id'))) : null; 130 $id = $request->getParam('lf_id') !== null ? intval(escape($request->getParam('lf_id'))) : null;
131 if (null !== $id && true === $this->container->bookmarkService->exists($id)) { 131 if (null !== $id && true === $this->container->bookmarkService->exists($id)) {
132 // Edit 132 // Edit
133 $bookmark = $this->container->bookmarkService->get($id); 133 $bookmark = $this->container->bookmarkService->get($id);
@@ -169,7 +169,7 @@ class ManageShaareController extends ShaarliAdminController
169 return $this->redirectFromReferer( 169 return $this->redirectFromReferer(
170 $request, 170 $request,
171 $response, 171 $response,
172 ['add-shaare', 'shaare'], ['addlink', 'post', 'edit_link'], 172 ['/admin/add-shaare', '/admin/shaare'], ['addlink', 'post', 'edit_link'],
173 $bookmark->getShortUrl() 173 $bookmark->getShortUrl()
174 ); 174 );
175 } 175 }
@@ -345,14 +345,14 @@ class ManageShaareController extends ShaarliAdminController
345 $tags[BookmarkMarkdownFormatter::NO_MD_TAG] = 1; 345 $tags[BookmarkMarkdownFormatter::NO_MD_TAG] = 1;
346 } 346 }
347 347
348 $data = [ 348 $data = escape([
349 'link' => $link, 349 'link' => $link,
350 'link_is_new' => $isNew, 350 'link_is_new' => $isNew,
351 'http_referer' => escape($this->container->environment['HTTP_REFERER'] ?? ''), 351 'http_referer' => $this->container->environment['HTTP_REFERER'] ?? '',
352 'source' => $request->getParam('source') ?? '', 352 'source' => $request->getParam('source') ?? '',
353 'tags' => $tags, 353 'tags' => $tags,
354 'default_private_links' => $this->container->conf->get('privacy.default_private_links', false), 354 'default_private_links' => $this->container->conf->get('privacy.default_private_links', false),
355 ]; 355 ]);
356 356
357 $this->executePageHooks('render_editlink', $data, TemplatePage::EDIT_LINK); 357 $this->executePageHooks('render_editlink', $data, TemplatePage::EDIT_LINK);
358 358
diff --git a/application/front/controller/admin/ManageTagController.php b/application/front/controller/admin/ManageTagController.php
index 0380ef1f..2065c3e2 100644
--- a/application/front/controller/admin/ManageTagController.php
+++ b/application/front/controller/admin/ManageTagController.php
@@ -41,8 +41,8 @@ class ManageTagController extends ShaarliAdminController
41 41
42 $isDelete = null !== $request->getParam('deletetag') && null === $request->getParam('renametag'); 42 $isDelete = null !== $request->getParam('deletetag') && null === $request->getParam('renametag');
43 43
44 $fromTag = escape(trim($request->getParam('fromtag') ?? '')); 44 $fromTag = trim($request->getParam('fromtag') ?? '');
45 $toTag = escape(trim($request->getParam('totag') ?? '')); 45 $toTag = trim($request->getParam('totag') ?? '');
46 46
47 if (0 === strlen($fromTag) || false === $isDelete && 0 === strlen($toTag)) { 47 if (0 === strlen($fromTag) || false === $isDelete && 0 === strlen($toTag)) {
48 $this->saveWarningMessage(t('Invalid tags provided.')); 48 $this->saveWarningMessage(t('Invalid tags provided.'));
diff --git a/application/front/controller/admin/PluginsController.php b/application/front/controller/admin/PluginsController.php
index 0e09116e..8e059681 100644
--- a/application/front/controller/admin/PluginsController.php
+++ b/application/front/controller/admin/PluginsController.php
@@ -62,6 +62,7 @@ class PluginsController extends ShaarliAdminController
62 62
63 if (isset($parameters['parameters_form'])) { 63 if (isset($parameters['parameters_form'])) {
64 unset($parameters['parameters_form']); 64 unset($parameters['parameters_form']);
65 unset($parameters['token']);
65 foreach ($parameters as $param => $value) { 66 foreach ($parameters as $param => $value) {
66 $this->container->conf->set('plugins.'. $param, escape($value)); 67 $this->container->conf->set('plugins.'. $param, escape($value));
67 } 68 }
diff --git a/application/front/controller/admin/ShaarliAdminController.php b/application/front/controller/admin/ShaarliAdminController.php
index 3b5939bb..c26c9cbe 100644
--- a/application/front/controller/admin/ShaarliAdminController.php
+++ b/application/front/controller/admin/ShaarliAdminController.php
@@ -4,9 +4,7 @@ declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Admin; 5namespace Shaarli\Front\Controller\Admin;
6 6
7use Shaarli\Container\ShaarliContainer;
8use Shaarli\Front\Controller\Visitor\ShaarliVisitorController; 7use Shaarli\Front\Controller\Visitor\ShaarliVisitorController;
9use Shaarli\Front\Exception\UnauthorizedException;
10use Shaarli\Front\Exception\WrongTokenException; 8use Shaarli\Front\Exception\WrongTokenException;
11use Shaarli\Security\SessionManager; 9use Shaarli\Security\SessionManager;
12use Slim\Http\Request; 10use Slim\Http\Request;
diff --git a/application/front/controller/visitor/BookmarkListController.php b/application/front/controller/visitor/BookmarkListController.php
index 2988bee6..18368751 100644
--- a/application/front/controller/visitor/BookmarkListController.php
+++ b/application/front/controller/visitor/BookmarkListController.php
@@ -34,7 +34,7 @@ class BookmarkListController extends ShaarliVisitorController
34 $formatter = $this->container->formatterFactory->getFormatter(); 34 $formatter = $this->container->formatterFactory->getFormatter();
35 $formatter->addContextData('base_path', $this->container->basePath); 35 $formatter->addContextData('base_path', $this->container->basePath);
36 36
37 $searchTags = escape(normalize_spaces($request->getParam('searchtags') ?? '')); 37 $searchTags = normalize_spaces($request->getParam('searchtags') ?? '');
38 $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));; 38 $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));;
39 39
40 // Filter bookmarks according search parameters. 40 // Filter bookmarks according search parameters.
@@ -104,8 +104,9 @@ class BookmarkListController extends ShaarliVisitorController
104 'page_current' => $page, 104 'page_current' => $page,
105 'page_max' => $pageCount, 105 'page_max' => $pageCount,
106 'result_count' => count($linksToDisplay), 106 'result_count' => count($linksToDisplay),
107 'search_term' => $searchTerm, 107 'search_term' => escape($searchTerm),
108 'search_tags' => $searchTags, 108 'search_tags' => escape($searchTags),
109 'search_tags_url' => array_map('urlencode', explode(' ', $searchTags)),
109 'visibility' => $visibility, 110 'visibility' => $visibility,
110 'links' => $linkDisp, 111 'links' => $linkDisp,
111 ] 112 ]
diff --git a/application/front/controller/visitor/DailyController.php b/application/front/controller/visitor/DailyController.php
index 54a4778f..07617cf1 100644
--- a/application/front/controller/visitor/DailyController.php
+++ b/application/front/controller/visitor/DailyController.php
@@ -132,7 +132,7 @@ class DailyController extends ShaarliVisitorController
132 'date' => $dayDatetime, 132 'date' => $dayDatetime,
133 'date_rss' => $dayDatetime->format(DateTime::RSS), 133 'date_rss' => $dayDatetime->format(DateTime::RSS),
134 'date_human' => format_date($dayDatetime, false, true), 134 'date_human' => format_date($dayDatetime, false, true),
135 'absolute_url' => $indexUrl . '/daily?day=' . $day, 135 'absolute_url' => $indexUrl . 'daily?day=' . $day,
136 'links' => [], 136 'links' => [],
137 ]; 137 ];
138 138
diff --git a/application/front/controller/visitor/ErrorNotFoundController.php b/application/front/controller/visitor/ErrorNotFoundController.php
new file mode 100644
index 00000000..758dd83b
--- /dev/null
+++ b/application/front/controller/visitor/ErrorNotFoundController.php
@@ -0,0 +1,29 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Visitor;
6
7use Slim\Http\Request;
8use Slim\Http\Response;
9
10/**
11 * Controller used to render the 404 error page.
12 */
13class ErrorNotFoundController extends ShaarliVisitorController
14{
15 public function __invoke(Request $request, Response $response): Response
16 {
17 // Request from the API
18 if (false !== strpos($request->getRequestTarget(), '/api/v1')) {
19 return $response->withStatus(404);
20 }
21
22 // This is required because the middleware is ignored if the route is not found.
23 $this->container->basePath = rtrim($request->getUri()->getBasePath(), '/');
24
25 $this->assignView('error_message', t('Requested page could not be found.'));
26
27 return $response->withStatus(404)->write($this->render('404'));
28 }
29}
diff --git a/application/front/controller/visitor/FeedController.php b/application/front/controller/visitor/FeedController.php
index da2848c2..8d8b546a 100644
--- a/application/front/controller/visitor/FeedController.php
+++ b/application/front/controller/visitor/FeedController.php
@@ -46,10 +46,10 @@ class FeedController extends ShaarliVisitorController
46 46
47 $data = $this->container->feedBuilder->buildData($feedType, $request->getParams()); 47 $data = $this->container->feedBuilder->buildData($feedType, $request->getParams());
48 48
49 $this->executePageHooks('render_feed', $data, $feedType); 49 $this->executePageHooks('render_feed', $data, 'feed.' . $feedType);
50 $this->assignAllView($data); 50 $this->assignAllView($data);
51 51
52 $content = $this->render('feed.'. $feedType); 52 $content = $this->render('feed.' . $feedType);
53 53
54 $cache->cache($content); 54 $cache->cache($content);
55 55
diff --git a/application/front/controller/visitor/ShaarliVisitorController.php b/application/front/controller/visitor/ShaarliVisitorController.php
index f17c8ed3..55c075a2 100644
--- a/application/front/controller/visitor/ShaarliVisitorController.php
+++ b/application/front/controller/visitor/ShaarliVisitorController.php
@@ -78,16 +78,14 @@ abstract class ShaarliVisitorController
78 'footer', 78 'footer',
79 ]; 79 ];
80 80
81 $parameters = $this->buildPluginParameters($template);
82
81 foreach ($common_hooks as $name) { 83 foreach ($common_hooks as $name) {
82 $pluginData = []; 84 $pluginData = [];
83 $this->container->pluginManager->executeHooks( 85 $this->container->pluginManager->executeHooks(
84 'render_' . $name, 86 'render_' . $name,
85 $pluginData, 87 $pluginData,
86 [ 88 $parameters
87 'target' => $template,
88 'loggedin' => $this->container->loginManager->isLoggedIn(),
89 'basePath' => $this->container->basePath,
90 ]
91 ); 89 );
92 $this->assignView('plugins_' . $name, $pluginData); 90 $this->assignView('plugins_' . $name, $pluginData);
93 } 91 }
@@ -95,19 +93,23 @@ abstract class ShaarliVisitorController
95 93
96 protected function executePageHooks(string $hook, array &$data, string $template = null): void 94 protected function executePageHooks(string $hook, array &$data, string $template = null): void
97 { 95 {
98 $params = [
99 'target' => $template,
100 'loggedin' => $this->container->loginManager->isLoggedIn(),
101 'basePath' => $this->container->basePath,
102 ];
103
104 $this->container->pluginManager->executeHooks( 96 $this->container->pluginManager->executeHooks(
105 $hook, 97 $hook,
106 $data, 98 $data,
107 $params 99 $this->buildPluginParameters($template)
108 ); 100 );
109 } 101 }
110 102
103 protected function buildPluginParameters(?string $template): array
104 {
105 return [
106 'target' => $template,
107 'loggedin' => $this->container->loginManager->isLoggedIn(),
108 'basePath' => $this->container->basePath,
109 'bookmarkService' => $this->container->bookmarkService
110 ];
111 }
112
111 /** 113 /**
112 * Simple helper which prepend the base path to redirect path. 114 * Simple helper which prepend the base path to redirect path.
113 * 115 *
@@ -140,6 +142,13 @@ abstract class ShaarliVisitorController
140 142
141 if (null !== $referer) { 143 if (null !== $referer) {
142 $currentUrl = parse_url($referer); 144 $currentUrl = parse_url($referer);
145 // If the referer is not related to Shaarli instance, redirect to default
146 if (isset($currentUrl['host'])
147 && strpos(index_url($this->container->environment), $currentUrl['host']) === false
148 ) {
149 return $response->withRedirect($defaultPath);
150 }
151
143 parse_str($currentUrl['query'] ?? '', $params); 152 parse_str($currentUrl['query'] ?? '', $params);
144 $path = $currentUrl['path'] ?? $defaultPath; 153 $path = $currentUrl['path'] ?? $defaultPath;
145 } else { 154 } else {
diff --git a/application/front/controller/visitor/TagCloudController.php b/application/front/controller/visitor/TagCloudController.php
index f9c529bc..76ed7690 100644
--- a/application/front/controller/visitor/TagCloudController.php
+++ b/application/front/controller/visitor/TagCloudController.php
@@ -66,10 +66,18 @@ class TagCloudController extends ShaarliVisitorController
66 $tags = $this->formatTagsForCloud($tags); 66 $tags = $this->formatTagsForCloud($tags);
67 } 67 }
68 68
69 $tagsUrl = [];
70 foreach ($tags as $tag => $value) {
71 $tagsUrl[escape($tag)] = urlencode((string) $tag);
72 }
73
69 $searchTags = implode(' ', escape($filteringTags)); 74 $searchTags = implode(' ', escape($filteringTags));
75 $searchTagsUrl = urlencode(implode(' ', $filteringTags));
70 $data = [ 76 $data = [
71 'search_tags' => $searchTags, 77 'search_tags' => escape($searchTags),
72 'tags' => $tags, 78 'search_tags_url' => $searchTagsUrl,
79 'tags' => escape($tags),
80 'tags_url' => $tagsUrl,
73 ]; 81 ];
74 $this->executePageHooks('render_tag' . $type, $data, 'tag.' . $type); 82 $this->executePageHooks('render_tag' . $type, $data, 'tag.' . $type);
75 $this->assignAllView($data); 83 $this->assignAllView($data);
diff --git a/application/http/HttpUtils.php b/application/http/HttpUtils.php
index 4fc4e3dc..9f414073 100644
--- a/application/http/HttpUtils.php
+++ b/application/http/HttpUtils.php
@@ -369,7 +369,11 @@ function server_url($server)
369 */ 369 */
370function index_url($server) 370function index_url($server)
371{ 371{
372 $scriptname = $server['SCRIPT_NAME'] ?? ''; 372 if (defined('SHAARLI_ROOT_URL') && null !== SHAARLI_ROOT_URL) {
373 return rtrim(SHAARLI_ROOT_URL, '/') . '/';
374 }
375
376 $scriptname = !empty($server['SCRIPT_NAME']) ? $server['SCRIPT_NAME'] : '/';
373 if (endsWith($scriptname, 'index.php')) { 377 if (endsWith($scriptname, 'index.php')) {
374 $scriptname = substr($scriptname, 0, -9); 378 $scriptname = substr($scriptname, 0, -9);
375 } 379 }
@@ -392,7 +396,7 @@ function page_url($server)
392 $scriptname = substr($scriptname, 0, -9); 396 $scriptname = substr($scriptname, 0, -9);
393 } 397 }
394 398
395 $route = ltrim($server['REQUEST_URI'] ?? '', $scriptname); 399 $route = preg_replace('@^' . $scriptname . '@', '', $server['REQUEST_URI'] ?? '');
396 if (! empty($server['QUERY_STRING'])) { 400 if (! empty($server['QUERY_STRING'])) {
397 return index_url($server) . $route . '?' . $server['QUERY_STRING']; 401 return index_url($server) . $route . '?' . $server['QUERY_STRING'];
398 } 402 }
diff --git a/application/legacy/LegacyController.php b/application/legacy/LegacyController.php
index e16dd0f4..826604e7 100644
--- a/application/legacy/LegacyController.php
+++ b/application/legacy/LegacyController.php
@@ -39,13 +39,23 @@ class LegacyController extends ShaarliVisitorController
39 /** Legacy route: ?post= */ 39 /** Legacy route: ?post= */
40 public function post(Request $request, Response $response): Response 40 public function post(Request $request, Response $response): Response
41 { 41 {
42 $parameters = count($request->getQueryParams()) > 0 ? '?' . http_build_query($request->getQueryParams()) : '';
43 $route = '/admin/shaare'; 42 $route = '/admin/shaare';
43 $buildParameters = function (?array $parameters, bool $encode) {
44 if ($encode) {
45 $parameters = array_map('urlencode', $parameters);
46 }
47
48 return count($parameters) > 0 ? '?' . http_build_query($parameters) : '';
49 };
50
44 51
45 if (!$this->container->loginManager->isLoggedIn()) { 52 if (!$this->container->loginManager->isLoggedIn()) {
53 $parameters = $buildParameters($request->getQueryParams(), true);
46 return $this->redirect($response, '/login?returnurl='. $this->getBasePath() . $route . $parameters); 54 return $this->redirect($response, '/login?returnurl='. $this->getBasePath() . $route . $parameters);
47 } 55 }
48 56
57 $parameters = $buildParameters($request->getQueryParams(), false);
58
49 return $this->redirect($response, $route . $parameters); 59 return $this->redirect($response, $route . $parameters);
50 } 60 }
51 61
diff --git a/application/legacy/LegacyRouter.php b/application/legacy/LegacyRouter.php
index cea99154..0449c7e1 100644
--- a/application/legacy/LegacyRouter.php
+++ b/application/legacy/LegacyRouter.php
@@ -17,15 +17,15 @@ class LegacyRouter
17 17
18 public static $PAGE_PICWALL = 'picwall'; 18 public static $PAGE_PICWALL = 'picwall';
19 19
20 public static $PAGE_TAGCLOUD = 'tagcloud'; 20 public static $PAGE_TAGCLOUD = 'tag.cloud';
21 21
22 public static $PAGE_TAGLIST = 'taglist'; 22 public static $PAGE_TAGLIST = 'tag.list';
23 23
24 public static $PAGE_DAILY = 'daily'; 24 public static $PAGE_DAILY = 'daily';
25 25
26 public static $PAGE_FEED_ATOM = 'atom'; 26 public static $PAGE_FEED_ATOM = 'feed.atom';
27 27
28 public static $PAGE_FEED_RSS = 'rss'; 28 public static $PAGE_FEED_RSS = 'feed.rss';
29 29
30 public static $PAGE_TOOLS = 'tools'; 30 public static $PAGE_TOOLS = 'tools';
31 31
@@ -37,7 +37,7 @@ class LegacyRouter
37 37
38 public static $PAGE_ADDLINK = 'addlink'; 38 public static $PAGE_ADDLINK = 'addlink';
39 39
40 public static $PAGE_EDITLINK = 'edit_link'; 40 public static $PAGE_EDITLINK = 'editlink';
41 41
42 public static $PAGE_DELETELINK = 'delete_link'; 42 public static $PAGE_DELETELINK = 'delete_link';
43 43
@@ -60,128 +60,4 @@ class LegacyRouter
60 public static $PAGE_THUMBS_UPDATE = 'thumbs_update'; 60 public static $PAGE_THUMBS_UPDATE = 'thumbs_update';
61 61
62 public static $GET_TOKEN = 'token'; 62 public static $GET_TOKEN = 'token';
63
64 /**
65 * Reproducing renderPage() if hell, to avoid regression.
66 *
67 * This highlights how bad this needs to be rewrite,
68 * but let's focus on plugins for now.
69 *
70 * @param string $query $_SERVER['QUERY_STRING'].
71 * @param array $get $_SERVER['GET'].
72 * @param bool $loggedIn true if authenticated user.
73 *
74 * @return string page found.
75 */
76 public static function findPage($query, $get, $loggedIn)
77 {
78 $loggedIn = ($loggedIn === true) ? true : false;
79
80 if (empty($query) && !isset($get['edit_link']) && !isset($get['post'])) {
81 return self::$PAGE_LINKLIST;
82 }
83
84 if (startsWith($query, 'do=' . self::$PAGE_LOGIN) && $loggedIn === false) {
85 return self::$PAGE_LOGIN;
86 }
87
88 if (startsWith($query, 'do=' . self::$PAGE_PICWALL)) {
89 return self::$PAGE_PICWALL;
90 }
91
92 if (startsWith($query, 'do=' . self::$PAGE_TAGCLOUD)) {
93 return self::$PAGE_TAGCLOUD;
94 }
95
96 if (startsWith($query, 'do=' . self::$PAGE_TAGLIST)) {
97 return self::$PAGE_TAGLIST;
98 }
99
100 if (startsWith($query, 'do=' . self::$PAGE_OPENSEARCH)) {
101 return self::$PAGE_OPENSEARCH;
102 }
103
104 if (startsWith($query, 'do=' . self::$PAGE_DAILY)) {
105 return self::$PAGE_DAILY;
106 }
107
108 if (startsWith($query, 'do=' . self::$PAGE_FEED_ATOM)) {
109 return self::$PAGE_FEED_ATOM;
110 }
111
112 if (startsWith($query, 'do=' . self::$PAGE_FEED_RSS)) {
113 return self::$PAGE_FEED_RSS;
114 }
115
116 if (startsWith($query, 'do=' . self::$PAGE_THUMBS_UPDATE)) {
117 return self::$PAGE_THUMBS_UPDATE;
118 }
119
120 if (startsWith($query, 'do=' . self::$AJAX_THUMB_UPDATE)) {
121 return self::$AJAX_THUMB_UPDATE;
122 }
123
124 // At this point, only loggedin pages.
125 if (!$loggedIn) {
126 return self::$PAGE_LINKLIST;
127 }
128
129 if (startsWith($query, 'do=' . self::$PAGE_TOOLS)) {
130 return self::$PAGE_TOOLS;
131 }
132
133 if (startsWith($query, 'do=' . self::$PAGE_CHANGEPASSWORD)) {
134 return self::$PAGE_CHANGEPASSWORD;
135 }
136
137 if (startsWith($query, 'do=' . self::$PAGE_CONFIGURE)) {
138 return self::$PAGE_CONFIGURE;
139 }
140
141 if (startsWith($query, 'do=' . self::$PAGE_CHANGETAG)) {
142 return self::$PAGE_CHANGETAG;
143 }
144
145 if (startsWith($query, 'do=' . self::$PAGE_ADDLINK)) {
146 return self::$PAGE_ADDLINK;
147 }
148
149 if (isset($get['edit_link']) || isset($get['post'])) {
150 return self::$PAGE_EDITLINK;
151 }
152
153 if (isset($get['delete_link'])) {
154 return self::$PAGE_DELETELINK;
155 }
156
157 if (isset($get[self::$PAGE_CHANGE_VISIBILITY])) {
158 return self::$PAGE_CHANGE_VISIBILITY;
159 }
160
161 if (startsWith($query, 'do=' . self::$PAGE_PINLINK)) {
162 return self::$PAGE_PINLINK;
163 }
164
165 if (startsWith($query, 'do=' . self::$PAGE_EXPORT)) {
166 return self::$PAGE_EXPORT;
167 }
168
169 if (startsWith($query, 'do=' . self::$PAGE_IMPORT)) {
170 return self::$PAGE_IMPORT;
171 }
172
173 if (startsWith($query, 'do=' . self::$PAGE_PLUGINSADMIN)) {
174 return self::$PAGE_PLUGINSADMIN;
175 }
176
177 if (startsWith($query, 'do=' . self::$PAGE_SAVE_PLUGINSADMIN)) {
178 return self::$PAGE_SAVE_PLUGINSADMIN;
179 }
180
181 if (startsWith($query, 'do=' . self::$GET_TOKEN)) {
182 return self::$GET_TOKEN;
183 }
184
185 return self::$PAGE_LINKLIST;
186 }
187} 63}
diff --git a/application/plugin/PluginManager.php b/application/plugin/PluginManager.php
index 2d93cb3a..1b2197c9 100644
--- a/application/plugin/PluginManager.php
+++ b/application/plugin/PluginManager.php
@@ -100,16 +100,17 @@ class PluginManager
100 */ 100 */
101 public function executeHooks($hook, &$data, $params = array()) 101 public function executeHooks($hook, &$data, $params = array())
102 { 102 {
103 if (!empty($params['target'])) { 103 $metadataParameters = [
104 $data['_PAGE_'] = $params['target']; 104 'target' => '_PAGE_',
105 } 105 'loggedin' => '_LOGGEDIN_',
106 106 'basePath' => '_BASE_PATH_',
107 if (isset($params['loggedin'])) { 107 'bookmarkService' => '_BOOKMARK_SERVICE_',
108 $data['_LOGGEDIN_'] = $params['loggedin']; 108 ];
109 } 109
110 110 foreach ($metadataParameters as $parameter => $metaKey) {
111 if (isset($params['basePath'])) { 111 if (array_key_exists($parameter, $params)) {
112 $data['_BASE_PATH_'] = $params['basePath']; 112 $data[$metaKey] = $params[$parameter];
113 }
113 } 114 }
114 115
115 foreach ($this->loadedPlugins as $plugin) { 116 foreach ($this->loadedPlugins as $plugin) {
@@ -124,6 +125,10 @@ class PluginManager
124 } 125 }
125 } 126 }
126 } 127 }
128
129 foreach ($metadataParameters as $metaKey) {
130 unset($data[$metaKey]);
131 }
127 } 132 }
128 133
129 /** 134 /**
diff --git a/application/render/PageBuilder.php b/application/render/PageBuilder.php
index c52e3b76..41b357dd 100644
--- a/application/render/PageBuilder.php
+++ b/application/render/PageBuilder.php
@@ -137,7 +137,7 @@ class PageBuilder
137 $this->tpl->assign('language', $this->conf->get('translation.language')); 137 $this->tpl->assign('language', $this->conf->get('translation.language'));
138 138
139 if ($this->bookmarkService !== null) { 139 if ($this->bookmarkService !== null) {
140 $this->tpl->assign('tags', $this->bookmarkService->bookmarksCountPerTag()); 140 $this->tpl->assign('tags', escape($this->bookmarkService->bookmarksCountPerTag()));
141 } 141 }
142 142
143 $this->tpl->assign( 143 $this->tpl->assign(