aboutsummaryrefslogtreecommitdiffhomepage
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/ApplicationUtils.php17
-rw-r--r--application/Base64Url.php7
-rw-r--r--application/FeedBuilder.php4
-rw-r--r--application/HttpUtils.php29
-rw-r--r--application/Languages.php15
-rw-r--r--application/LinkDB.php32
-rw-r--r--application/LinkFilter.php25
-rw-r--r--application/LinkUtils.php5
-rw-r--r--application/NetscapeBookmarkUtils.php16
-rw-r--r--application/PageBuilder.php5
-rw-r--r--application/PluginManager.php3
-rw-r--r--application/Router.php6
-rw-r--r--application/Thumbnailer.php5
-rw-r--r--application/Updater.php22
-rw-r--r--application/Url.php19
-rw-r--r--application/Utils.php16
-rw-r--r--application/api/ApiMiddleware.php5
-rw-r--r--application/api/controllers/ApiController.php2
-rw-r--r--application/api/controllers/History.php3
-rw-r--r--application/api/controllers/Info.php4
-rw-r--r--application/api/exceptions/ApiException.php8
-rw-r--r--application/api/exceptions/ApiLinkNotFoundException.php1
-rw-r--r--application/api/exceptions/ApiTagNotFoundException.php1
-rw-r--r--application/config/ConfigPhp.php12
-rw-r--r--application/config/ConfigPlugin.php3
-rw-r--r--application/security/LoginManager.php1
26 files changed, 162 insertions, 104 deletions
diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php
index 911873a0..a3b2dcb1 100644
--- a/application/ApplicationUtils.php
+++ b/application/ApplicationUtils.php
@@ -24,7 +24,7 @@ class ApplicationUtils
24 * 24 *
25 * @return mixed the version code from the repository if available, else 'false' 25 * @return mixed the version code from the repository if available, else 'false'
26 */ 26 */
27 public static function getLatestGitVersionCode($url, $timeout=2) 27 public static function getLatestGitVersionCode($url, $timeout = 2)
28 { 28 {
29 list($headers, $data) = get_http_response($url, $timeout); 29 list($headers, $data) = get_http_response($url, $timeout);
30 30
@@ -86,13 +86,14 @@ class ApplicationUtils
86 * 86 *
87 * @return mixed the new version code if available and greater, else 'false' 87 * @return mixed the new version code if available and greater, else 'false'
88 */ 88 */
89 public static function checkUpdate($currentVersion, 89 public static function checkUpdate(
90 $updateFile, 90 $currentVersion,
91 $checkInterval, 91 $updateFile,
92 $enableCheck, 92 $checkInterval,
93 $isLoggedIn, 93 $enableCheck,
94 $branch='stable') 94 $isLoggedIn,
95 { 95 $branch = 'stable'
96 ) {
96 // Do not check versions for visitors 97 // Do not check versions for visitors
97 // Do not check if the user doesn't want to 98 // Do not check if the user doesn't want to
98 // Do not check with dev version 99 // Do not check with dev version
diff --git a/application/Base64Url.php b/application/Base64Url.php
index 61590e43..54d0fcd5 100644
--- a/application/Base64Url.php
+++ b/application/Base64Url.php
@@ -2,7 +2,6 @@
2 2
3namespace Shaarli; 3namespace Shaarli;
4 4
5
6/** 5/**
7 * URL-safe Base64 operations 6 * URL-safe Base64 operations
8 * 7 *
@@ -17,7 +16,8 @@ class Base64Url
17 * 16 *
18 * @return string Base64Url-encoded data 17 * @return string Base64Url-encoded data
19 */ 18 */
20 public static function encode($data) { 19 public static function encode($data)
20 {
21 return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); 21 return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
22 } 22 }
23 23
@@ -28,7 +28,8 @@ class Base64Url
28 * 28 *
29 * @return string Decoded data 29 * @return string Decoded data
30 */ 30 */
31 public static function decode($data) { 31 public static function decode($data)
32 {
32 return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); 33 return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
33 } 34 }
34} 35}
diff --git a/application/FeedBuilder.php b/application/FeedBuilder.php
index ebae18b4..73fafcbe 100644
--- a/application/FeedBuilder.php
+++ b/application/FeedBuilder.php
@@ -163,7 +163,8 @@ class FeedBuilder
163 $upDate = $link['updated']; 163 $upDate = $link['updated'];
164 $link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM); 164 $link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM);
165 } else { 165 } else {
166 $link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);; 166 $link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);
167 ;
167 } 168 }
168 169
169 // Save the more recent item. 170 // Save the more recent item.
@@ -261,7 +262,6 @@ class FeedBuilder
261 } 262 }
262 if ($this->feedType == self::$FEED_RSS) { 263 if ($this->feedType == self::$FEED_RSS) {
263 return $date->format(DateTime::RSS); 264 return $date->format(DateTime::RSS);
264
265 } 265 }
266 return $date->format(DateTime::ATOM); 266 return $date->format(DateTime::ATOM);
267 } 267 }
diff --git a/application/HttpUtils.php b/application/HttpUtils.php
index e9282506..9c438160 100644
--- a/application/HttpUtils.php
+++ b/application/HttpUtils.php
@@ -7,7 +7,8 @@
7 * @param int $timeout network timeout (in seconds) 7 * @param int $timeout network timeout (in seconds)
8 * @param int $maxBytes maximum downloaded bytes (default: 4 MiB) 8 * @param int $maxBytes maximum downloaded bytes (default: 4 MiB)
9 * @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION). 9 * @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION).
10 * Can be used to add download conditions on the headers (response code, content type, etc.). 10 * Can be used to add download conditions on the
11 * headers (response code, content type, etc.).
11 * 12 *
12 * @return array HTTP response headers, downloaded content 13 * @return array HTTP response headers, downloaded content
13 * 14 *
@@ -64,29 +65,30 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304, $curlWriteF
64 } 65 }
65 66
66 // General cURL settings 67 // General cURL settings
67 curl_setopt($ch, CURLOPT_AUTOREFERER, true); 68 curl_setopt($ch, CURLOPT_AUTOREFERER, true);
68 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 69 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
69 curl_setopt($ch, CURLOPT_HEADER, true); 70 curl_setopt($ch, CURLOPT_HEADER, true);
70 curl_setopt( 71 curl_setopt(
71 $ch, 72 $ch,
72 CURLOPT_HTTPHEADER, 73 CURLOPT_HTTPHEADER,
73 array('Accept-Language: ' . $acceptLanguage) 74 array('Accept-Language: ' . $acceptLanguage)
74 ); 75 );
75 curl_setopt($ch, CURLOPT_MAXREDIRS, $maxRedirs); 76 curl_setopt($ch, CURLOPT_MAXREDIRS, $maxRedirs);
76 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 77 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
77 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); 78 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
78 curl_setopt($ch, CURLOPT_USERAGENT, $userAgent); 79 curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
79 80
80 if (is_callable($curlWriteFunction)) { 81 if (is_callable($curlWriteFunction)) {
81 curl_setopt($ch, CURLOPT_WRITEFUNCTION, $curlWriteFunction); 82 curl_setopt($ch, CURLOPT_WRITEFUNCTION, $curlWriteFunction);
82 } 83 }
83 84
84 // Max download size management 85 // Max download size management
85 curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16); 86 curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16);
86 curl_setopt($ch, CURLOPT_NOPROGRESS, false); 87 curl_setopt($ch, CURLOPT_NOPROGRESS, false);
87 curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 88 curl_setopt(
88 function($arg0, $arg1, $arg2, $arg3, $arg4 = 0) use ($maxBytes) 89 $ch,
89 { 90 CURLOPT_PROGRESSFUNCTION,
91 function ($arg0, $arg1, $arg2, $arg3, $arg4 = 0) use ($maxBytes) {
90 if (version_compare(phpversion(), '5.5', '<')) { 92 if (version_compare(phpversion(), '5.5', '<')) {
91 // PHP version lower than 5.5 93 // PHP version lower than 5.5
92 // Callback has 4 arguments 94 // Callback has 4 arguments
@@ -232,7 +234,6 @@ function get_redirected_headers($url, $redirectionLimit = 3)
232 && !empty($headers) 234 && !empty($headers)
233 && (strpos($headers[0], '301') !== false || strpos($headers[0], '302') !== false) 235 && (strpos($headers[0], '301') !== false || strpos($headers[0], '302') !== false)
234 && !empty($headers['Location'])) { 236 && !empty($headers['Location'])) {
235
236 $redirection = is_array($headers['Location']) ? end($headers['Location']) : $headers['Location']; 237 $redirection = is_array($headers['Location']) ? end($headers['Location']) : $headers['Location'];
237 if ($redirection != $url) { 238 if ($redirection != $url) {
238 $redirection = getAbsoluteUrl($url, $redirection); 239 $redirection = getAbsoluteUrl($url, $redirection);
diff --git a/application/Languages.php b/application/Languages.php
index 4fa32426..b9c5d0e8 100644
--- a/application/Languages.php
+++ b/application/Languages.php
@@ -92,7 +92,7 @@ class Languages
92 /** 92 /**
93 * Initialize the translator using php gettext extension (gettext dependency act as a wrapper). 93 * Initialize the translator using php gettext extension (gettext dependency act as a wrapper).
94 */ 94 */
95 protected function initGettextTranslator () 95 protected function initGettextTranslator()
96 { 96 {
97 $this->translator = new GettextTranslator(); 97 $this->translator = new GettextTranslator();
98 $this->translator->setLanguage($this->language); 98 $this->translator->setLanguage($this->language);
@@ -125,7 +125,8 @@ class Languages
125 $translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po'); 125 $translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
126 $translations->setDomain('shaarli'); 126 $translations->setDomain('shaarli');
127 $this->translator->loadTranslations($translations); 127 $this->translator->loadTranslations($translations);
128 } catch (\InvalidArgumentException $e) {} 128 } catch (\InvalidArgumentException $e) {
129 }
129 130
130 // Default extension translation from the current theme 131 // Default extension translation from the current theme
131 $theme = $this->conf->get('theme'); 132 $theme = $this->conf->get('theme');
@@ -137,7 +138,8 @@ class Languages
137 ); 138 );
138 $translations->setDomain($theme); 139 $translations->setDomain($theme);
139 $this->translator->loadTranslations($translations); 140 $this->translator->loadTranslations($translations);
140 } catch (\InvalidArgumentException $e) {} 141 } catch (\InvalidArgumentException $e) {
142 }
141 } 143 }
142 144
143 // Extension translations (plugins, themes, etc.). 145 // Extension translations (plugins, themes, etc.).
@@ -147,10 +149,13 @@ class Languages
147 } 149 }
148 150
149 try { 151 try {
150 $extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'); 152 $extension = Translations::fromPoFile(
153 $translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'
154 );
151 $extension->setDomain($domain); 155 $extension->setDomain($domain);
152 $this->translator->loadTranslations($extension); 156 $this->translator->loadTranslations($extension);
153 } catch (\InvalidArgumentException $e) {} 157 } catch (\InvalidArgumentException $e) {
158 }
154 } 159 }
155 } 160 }
156 161
diff --git a/application/LinkDB.php b/application/LinkDB.php
index cd0f2967..4bbc2950 100644
--- a/application/LinkDB.php
+++ b/application/LinkDB.php
@@ -107,8 +107,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
107 $hidePublicLinks, 107 $hidePublicLinks,
108 $redirector = '', 108 $redirector = '',
109 $redirectorEncode = true 109 $redirectorEncode = true
110 ) 110 ) {
111 {
112 $this->datastore = $datastore; 111 $this->datastore = $datastore;
113 $this->loggedIn = $isLoggedIn; 112 $this->loggedIn = $isLoggedIn;
114 $this->hidePublicLinks = $hidePublicLinks; 113 $this->hidePublicLinks = $hidePublicLinks;
@@ -250,11 +249,14 @@ class LinkDB implements Iterator, Countable, ArrayAccess
250 'id' => 1, 249 'id' => 1,
251 'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'), 250 'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'),
252 'url'=>'https://shaarli.readthedocs.io', 251 'url'=>'https://shaarli.readthedocs.io',
253 'description'=>t('Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. 252 'description'=>t(
253 'Welcome to Shaarli! This is your first public bookmark. '
254 .'To edit or delete me, you must first login.
254 255
255To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page. 256To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page.
256 257
257You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'), 258You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'
259 ),
258 'private'=>0, 260 'private'=>0,
259 'created'=> new DateTime(), 261 'created'=> new DateTime(),
260 'tags'=>'opensource software' 262 'tags'=>'opensource software'
@@ -317,8 +319,7 @@ You use the community supported version of the original Shaarli project, by Seba
317 } else { 319 } else {
318 $link['real_url'] .= $link['url']; 320 $link['real_url'] .= $link['url'];
319 } 321 }
320 } 322 } else {
321 else {
322 $link['real_url'] = $link['url']; 323 $link['real_url'] = $link['url'];
323 } 324 }
324 325
@@ -403,7 +404,8 @@ You use the community supported version of the original Shaarli project, by Seba
403 * 404 *
404 * @return array list of shaare found. 405 * @return array list of shaare found.
405 */ 406 */
406 public function filterDay($request) { 407 public function filterDay($request)
408 {
407 $linkFilter = new LinkFilter($this->links); 409 $linkFilter = new LinkFilter($this->links);
408 return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request); 410 return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request);
409 } 411 }
@@ -420,8 +422,12 @@ You use the community supported version of the original Shaarli project, by Seba
420 * 422 *
421 * @return array filtered links, all links if no suitable filter was provided. 423 * @return array filtered links, all links if no suitable filter was provided.
422 */ 424 */
423 public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all', $untaggedonly = false) 425 public function filterSearch(
424 { 426 $filterRequest = array(),
427 $casesensitive = false,
428 $visibility = 'all',
429 $untaggedonly = false
430 ) {
425 // Filter link database according to parameters. 431 // Filter link database according to parameters.
426 $searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : ''; 432 $searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
427 $searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : ''; 433 $searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
@@ -492,8 +498,7 @@ You use the community supported version of the original Shaarli project, by Seba
492 $delete = empty($to); 498 $delete = empty($to);
493 // True for case-sensitive tag search. 499 // True for case-sensitive tag search.
494 $linksToAlter = $this->filterSearch(['searchtags' => $from], true); 500 $linksToAlter = $this->filterSearch(['searchtags' => $from], true);
495 foreach($linksToAlter as $key => &$value) 501 foreach ($linksToAlter as $key => &$value) {
496 {
497 $tags = preg_split('/\s+/', trim($value['tags'])); 502 $tags = preg_split('/\s+/', trim($value['tags']));
498 if (($pos = array_search($from, $tags)) !== false) { 503 if (($pos = array_search($from, $tags)) !== false) {
499 if ($delete) { 504 if ($delete) {
@@ -536,7 +541,10 @@ You use the community supported version of the original Shaarli project, by Seba
536 { 541 {
537 $order = $order === 'ASC' ? -1 : 1; 542 $order = $order === 'ASC' ? -1 : 1;
538 // Reorder array by dates. 543 // Reorder array by dates.
539 usort($this->links, function($a, $b) use ($order) { 544 usort($this->links, function ($a, $b) use ($order) {
545 if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) {
546 return $a['sticky'] ? -1 : 1;
547 }
540 return $a['created'] < $b['created'] ? 1 * $order : -1 * $order; 548 return $a['created'] < $b['created'] ? 1 * $order : -1 * $order;
541 }); 549 });
542 550
diff --git a/application/LinkFilter.php b/application/LinkFilter.php
index e52239b8..8f147974 100644
--- a/application/LinkFilter.php
+++ b/application/LinkFilter.php
@@ -62,7 +62,7 @@ class LinkFilter
62 $visibility = 'all'; 62 $visibility = 'all';
63 } 63 }
64 64
65 switch($type) { 65 switch ($type) {
66 case self::$FILTER_HASH: 66 case self::$FILTER_HASH:
67 return $this->filterSmallHash($request); 67 return $this->filterSmallHash($request);
68 case self::$FILTER_TAG | self::$FILTER_TEXT: // == "vuotext" 68 case self::$FILTER_TAG | self::$FILTER_TEXT: // == "vuotext"
@@ -205,7 +205,6 @@ class LinkFilter
205 205
206 // Iterate over every stored link. 206 // Iterate over every stored link.
207 foreach ($this->links as $id => $link) { 207 foreach ($this->links as $id => $link) {
208
209 // ignore non private links when 'privatonly' is on. 208 // ignore non private links when 'privatonly' is on.
210 if ($visibility !== 'all') { 209 if ($visibility !== 'all') {
211 if (! $link['private'] && $visibility === 'private') { 210 if (! $link['private'] && $visibility === 'private') {
@@ -257,11 +256,11 @@ class LinkFilter
257 private static function tag2regex($tag) 256 private static function tag2regex($tag)
258 { 257 {
259 $len = strlen($tag); 258 $len = strlen($tag);
260 if(!$len || $tag === "-" || $tag === "*"){ 259 if (!$len || $tag === "-" || $tag === "*") {
261 // nothing to search, return empty regex 260 // nothing to search, return empty regex
262 return ''; 261 return '';
263 } 262 }
264 if($tag[0] === "-") { 263 if ($tag[0] === "-") {
265 // query is negated 264 // query is negated
266 $i = 1; // use offset to start after '-' character 265 $i = 1; // use offset to start after '-' character
267 $regex = '(?!'; // create negative lookahead 266 $regex = '(?!'; // create negative lookahead
@@ -271,14 +270,14 @@ class LinkFilter
271 } 270 }
272 $regex .= '.*(?:^| )'; // before tag may only be a space or the beginning 271 $regex .= '.*(?:^| )'; // before tag may only be a space or the beginning
273 // iterate over string, separating it into placeholder and content 272 // iterate over string, separating it into placeholder and content
274 for(; $i < $len; $i++){ 273 for (; $i < $len; $i++) {
275 if($tag[$i] === '*'){ 274 if ($tag[$i] === '*') {
276 // placeholder found 275 // placeholder found
277 $regex .= '[^ ]*?'; 276 $regex .= '[^ ]*?';
278 } else { 277 } else {
279 // regular characters 278 // regular characters
280 $offset = strpos($tag, '*', $i); 279 $offset = strpos($tag, '*', $i);
281 if($offset === false){ 280 if ($offset === false) {
282 // no placeholder found, set offset to end of string 281 // no placeholder found, set offset to end of string
283 $offset = $len; 282 $offset = $len;
284 } 283 }
@@ -310,19 +309,19 @@ class LinkFilter
310 { 309 {
311 // get single tags (we may get passed an array, even though the docs say different) 310 // get single tags (we may get passed an array, even though the docs say different)
312 $inputTags = $tags; 311 $inputTags = $tags;
313 if(!is_array($tags)) { 312 if (!is_array($tags)) {
314 // we got an input string, split tags 313 // we got an input string, split tags
315 $inputTags = preg_split('/(?:\s+)|,/', $inputTags, -1, PREG_SPLIT_NO_EMPTY); 314 $inputTags = preg_split('/(?:\s+)|,/', $inputTags, -1, PREG_SPLIT_NO_EMPTY);
316 } 315 }
317 316
318 if(!count($inputTags)){ 317 if (!count($inputTags)) {
319 // no input tags 318 // no input tags
320 return $this->noFilter($visibility); 319 return $this->noFilter($visibility);
321 } 320 }
322 321
323 // build regex from all tags 322 // build regex from all tags
324 $re = '/^' . implode(array_map("self::tag2regex", $inputTags)) . '.*$/'; 323 $re = '/^' . implode(array_map("self::tag2regex", $inputTags)) . '.*$/';
325 if(!$casesensitive) { 324 if (!$casesensitive) {
326 // make regex case insensitive 325 // make regex case insensitive
327 $re .= 'i'; 326 $re .= 'i';
328 } 327 }
@@ -342,7 +341,7 @@ class LinkFilter
342 } 341 }
343 } 342 }
344 $search = $link['tags']; // build search string, start with tags of current link 343 $search = $link['tags']; // build search string, start with tags of current link
345 if(strlen(trim($link['description'])) && strpos($link['description'], '#') !== false){ 344 if (strlen(trim($link['description'])) && strpos($link['description'], '#') !== false) {
346 // description given and at least one possible tag found 345 // description given and at least one possible tag found
347 $descTags = array(); 346 $descTags = array();
348 // find all tags in the form of #tag in the description 347 // find all tags in the form of #tag in the description
@@ -351,13 +350,13 @@ class LinkFilter
351 $link['description'], 350 $link['description'],
352 $descTags 351 $descTags
353 ); 352 );
354 if(count($descTags[1])){ 353 if (count($descTags[1])) {
355 // there were some tags in the description, add them to the search string 354 // there were some tags in the description, add them to the search string
356 $search .= ' ' . implode(' ', $descTags[1]); 355 $search .= ' ' . implode(' ', $descTags[1]);
357 } 356 }
358 }; 357 };
359 // match regular expression with search string 358 // match regular expression with search string
360 if(!preg_match($re, $search)){ 359 if (!preg_match($re, $search)) {
361 // this entry does _not_ match our regex 360 // this entry does _not_ match our regex
362 continue; 361 continue;
363 } 362 }
diff --git a/application/LinkUtils.php b/application/LinkUtils.php
index 4df5c0ca..d56e019f 100644
--- a/application/LinkUtils.php
+++ b/application/LinkUtils.php
@@ -23,7 +23,7 @@ function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_get
23 * 23 *
24 * @return int|bool length of $data or false if we need to stop the download 24 * @return int|bool length of $data or false if we need to stop the download
25 */ 25 */
26 return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) { 26 return function (&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) {
27 $responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE); 27 $responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE);
28 if (!empty($responseCode) && in_array($responseCode, [301, 302])) { 28 if (!empty($responseCode) && in_array($responseCode, [301, 302])) {
29 $isRedirected = true; 29 $isRedirected = true;
@@ -201,7 +201,8 @@ function space2nbsp($text)
201 201
202 * @return string formatted description. 202 * @return string formatted description.
203 */ 203 */
204function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '') { 204function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '')
205{
205 return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector, $urlEncode), $indexUrl))); 206 return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector, $urlEncode), $indexUrl)));
206} 207}
207 208
diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php
index b4d16d00..84dd2b20 100644
--- a/application/NetscapeBookmarkUtils.php
+++ b/application/NetscapeBookmarkUtils.php
@@ -72,18 +72,20 @@ class NetscapeBookmarkUtils
72 private static function importStatus( 72 private static function importStatus(
73 $filename, 73 $filename,
74 $filesize, 74 $filesize,
75 $importCount=0, 75 $importCount = 0,
76 $overwriteCount=0, 76 $overwriteCount = 0,
77 $skipCount=0, 77 $skipCount = 0,
78 $duration=0 78 $duration = 0
79 ) 79 ) {
80 {
81 $status = sprintf(t('File %s (%d bytes) '), $filename, $filesize); 80 $status = sprintf(t('File %s (%d bytes) '), $filename, $filesize);
82 if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) { 81 if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) {
83 $status .= t('has an unknown file format. Nothing was imported.'); 82 $status .= t('has an unknown file format. Nothing was imported.');
84 } else { 83 } else {
85 $status .= vsprintf( 84 $status .= vsprintf(
86 t('was successfully processed in %d seconds: %d links imported, %d links overwritten, %d links skipped.'), 85 t(
86 'was successfully processed in %d seconds: '
87 .'%d links imported, %d links overwritten, %d links skipped.'
88 ),
87 [$duration, $importCount, $overwriteCount, $skipCount] 89 [$duration, $importCount, $overwriteCount, $skipCount]
88 ); 90 );
89 } 91 }
diff --git a/application/PageBuilder.php b/application/PageBuilder.php
index b1abe0d0..2ca95832 100644
--- a/application/PageBuilder.php
+++ b/application/PageBuilder.php
@@ -78,7 +78,6 @@ class PageBuilder
78 ); 78 );
79 $this->tpl->assign('newVersion', escape($version)); 79 $this->tpl->assign('newVersion', escape($version));
80 $this->tpl->assign('versionError', ''); 80 $this->tpl->assign('versionError', '');
81
82 } catch (Exception $exc) { 81 } catch (Exception $exc) {
83 logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage()); 82 logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage());
84 $this->tpl->assign('newVersion', ''); 83 $this->tpl->assign('newVersion', '');
@@ -101,7 +100,7 @@ class PageBuilder
101 'version_hash', 100 'version_hash',
102 ApplicationUtils::getVersionHash(SHAARLI_VERSION, $this->conf->get('credentials.salt')) 101 ApplicationUtils::getVersionHash(SHAARLI_VERSION, $this->conf->get('credentials.salt'))
103 ); 102 );
104 $this->tpl->assign('scripturl', index_url($_SERVER)); 103 $this->tpl->assign('index_url', index_url($_SERVER));
105 $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : ''; 104 $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '';
106 $this->tpl->assign('visibility', $visibility); 105 $this->tpl->assign('visibility', $visibility);
107 $this->tpl->assign('untaggedonly', !empty($_SESSION['untaggedonly'])); 106 $this->tpl->assign('untaggedonly', !empty($_SESSION['untaggedonly']));
@@ -163,7 +162,7 @@ class PageBuilder
163 $this->initialize(); 162 $this->initialize();
164 } 163 }
165 164
166 if (empty($data) || !is_array($data)){ 165 if (empty($data) || !is_array($data)) {
167 return false; 166 return false;
168 } 167 }
169 168
diff --git a/application/PluginManager.php b/application/PluginManager.php
index cf603845..1ed4db4b 100644
--- a/application/PluginManager.php
+++ b/application/PluginManager.php
@@ -75,8 +75,7 @@ class PluginManager
75 75
76 try { 76 try {
77 $this->loadPlugin($dirs[$index], $plugin); 77 $this->loadPlugin($dirs[$index], $plugin);
78 } 78 } catch (PluginFileNotFoundException $e) {
79 catch (PluginFileNotFoundException $e) {
80 error_log($e->getMessage()); 79 error_log($e->getMessage());
81 } 80 }
82 } 81 }
diff --git a/application/Router.php b/application/Router.php
index bf86b884..beb3165b 100644
--- a/application/Router.php
+++ b/application/Router.php
@@ -37,6 +37,8 @@ class Router
37 37
38 public static $PAGE_DELETELINK = 'delete_link'; 38 public static $PAGE_DELETELINK = 'delete_link';
39 39
40 public static $PAGE_PINLINK = 'pin';
41
40 public static $PAGE_EXPORT = 'export'; 42 public static $PAGE_EXPORT = 'export';
41 43
42 public static $PAGE_IMPORT = 'import'; 44 public static $PAGE_IMPORT = 'import';
@@ -146,6 +148,10 @@ class Router
146 return self::$PAGE_DELETELINK; 148 return self::$PAGE_DELETELINK;
147 } 149 }
148 150
151 if (startsWith($query, 'do='. self::$PAGE_PINLINK)) {
152 return self::$PAGE_PINLINK;
153 }
154
149 if (startsWith($query, 'do='. self::$PAGE_EXPORT)) { 155 if (startsWith($query, 'do='. self::$PAGE_EXPORT)) {
150 return self::$PAGE_EXPORT; 156 return self::$PAGE_EXPORT;
151 } 157 }
diff --git a/application/Thumbnailer.php b/application/Thumbnailer.php
index 7d0d9c33..37ed97a1 100644
--- a/application/Thumbnailer.php
+++ b/application/Thumbnailer.php
@@ -58,7 +58,10 @@ class Thumbnailer
58 $this->conf->set('thumbnails.enabled', false); 58 $this->conf->set('thumbnails.enabled', false);
59 $this->conf->write(true); 59 $this->conf->write(true);
60 // TODO: create a proper error handling system able to catch exceptions... 60 // TODO: create a proper error handling system able to catch exceptions...
61 die(t('php-gd extension must be loaded to use thumbnails. Thumbnails are now disabled. Please reload the page.')); 61 die(t(
62 'php-gd extension must be loaded to use thumbnails. '
63 .'Thumbnails are now disabled. Please reload the page.'
64 ));
62 } 65 }
63 66
64 $this->wt = new WebThumbnailer(); 67 $this->wt = new WebThumbnailer();
diff --git a/application/Updater.php b/application/Updater.php
index 480bff82..6b94c5e3 100644
--- a/application/Updater.php
+++ b/application/Updater.php
@@ -183,7 +183,7 @@ class Updater
183 } 183 }
184 } 184 }
185 185
186 try{ 186 try {
187 $this->conf->write($this->isLoggedIn); 187 $this->conf->write($this->isLoggedIn);
188 return true; 188 return true;
189 } catch (IOException $e) { 189 } catch (IOException $e) {
@@ -517,6 +517,26 @@ class Updater
517 517
518 return true; 518 return true;
519 } 519 }
520
521 /**
522 * Set sticky = false on all links
523 *
524 * @return bool true if the update is successful, false otherwise.
525 */
526 public function updateMethodSetSticky()
527 {
528 foreach ($this->linkDB as $key => $link) {
529 if (isset($link['sticky'])) {
530 return true;
531 }
532 $link['sticky'] = false;
533 $this->linkDB[$key] = $link;
534 }
535
536 $this->linkDB->save($this->conf->get('resource.page_cache'));
537
538 return true;
539 }
520} 540}
521 541
522/** 542/**
diff --git a/application/Url.php b/application/Url.php
index 6b9870f0..3b7f19c2 100644
--- a/application/Url.php
+++ b/application/Url.php
@@ -34,8 +34,8 @@ function unparse_url($parsedUrl)
34 */ 34 */
35function cleanup_url($url) 35function cleanup_url($url)
36{ 36{
37 $obj_url = new Url($url); 37 $obj_url = new Url($url);
38 return $obj_url->cleanup(); 38 return $obj_url->cleanup();
39} 39}
40 40
41/** 41/**
@@ -47,8 +47,8 @@ function cleanup_url($url)
47 */ 47 */
48function get_url_scheme($url) 48function get_url_scheme($url)
49{ 49{
50 $obj_url = new Url($url); 50 $obj_url = new Url($url);
51 return $obj_url->getScheme(); 51 return $obj_url->getScheme();
52} 52}
53 53
54/** 54/**
@@ -217,7 +217,7 @@ class Url
217 } 217 }
218 218
219 $this->parts['query'] = implode('&', $queryParams); 219 $this->parts['query'] = implode('&', $queryParams);
220 } 220 }
221 221
222 /** 222 /**
223 * Removes undesired fragments 223 * Removes undesired fragments
@@ -269,7 +269,8 @@ class Url
269 * 269 *
270 * @return string the URL scheme or false if none is provided. 270 * @return string the URL scheme or false if none is provided.
271 */ 271 */
272 public function getScheme() { 272 public function getScheme()
273 {
273 if (!isset($this->parts['scheme'])) { 274 if (!isset($this->parts['scheme'])) {
274 return false; 275 return false;
275 } 276 }
@@ -281,7 +282,8 @@ class Url
281 * 282 *
282 * @return string the URL host or false if none is provided. 283 * @return string the URL host or false if none is provided.
283 */ 284 */
284 public function getHost() { 285 public function getHost()
286 {
285 if (empty($this->parts['host'])) { 287 if (empty($this->parts['host'])) {
286 return false; 288 return false;
287 } 289 }
@@ -293,7 +295,8 @@ class Url
293 * 295 *
294 * @return true is HTTP, false otherwise. 296 * @return true is HTTP, false otherwise.
295 */ 297 */
296 public function isHttp() { 298 public function isHttp()
299 {
297 return strpos(strtolower($this->parts['scheme']), 'http') !== false; 300 return strpos(strtolower($this->parts['scheme']), 'http') !== false;
298 } 301 }
299} 302}
diff --git a/application/Utils.php b/application/Utils.php
index 97b12fcf..925e1a22 100644
--- a/application/Utils.php
+++ b/application/Utils.php
@@ -97,7 +97,7 @@ function escape($input)
97 97
98 if (is_array($input)) { 98 if (is_array($input)) {
99 $out = array(); 99 $out = array();
100 foreach($input as $key => $value) { 100 foreach ($input as $key => $value) {
101 $out[$key] = escape($value); 101 $out[$key] = escape($value);
102 } 102 }
103 return $out; 103 return $out;
@@ -355,10 +355,13 @@ function return_bytes($val)
355 $val = trim($val); 355 $val = trim($val);
356 $last = strtolower($val[strlen($val)-1]); 356 $last = strtolower($val[strlen($val)-1]);
357 $val = intval(substr($val, 0, -1)); 357 $val = intval(substr($val, 0, -1));
358 switch($last) { 358 switch ($last) {
359 case 'g': $val *= 1024; 359 case 'g':
360 case 'm': $val *= 1024; 360 $val *= 1024;
361 case 'k': $val *= 1024; 361 case 'm':
362 $val *= 1024;
363 case 'k':
364 $val *= 1024;
362 } 365 }
363 return $val; 366 return $val;
364} 367}
@@ -452,6 +455,7 @@ function alphabetical_sort(&$data, $reverse = false, $byKeys = false)
452 * 455 *
453 * @return string Text translated. 456 * @return string Text translated.
454 */ 457 */
455function t($text, $nText = '', $nb = 1, $domain = 'shaarli') { 458function t($text, $nText = '', $nb = 1, $domain = 'shaarli')
459{
456 return dn__($domain, $text, $nText, $nb); 460 return dn__($domain, $text, $nText, $nb);
457} 461}
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index ff209393..66eac133 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -65,7 +65,7 @@ class ApiMiddleware
65 try { 65 try {
66 $this->checkRequest($request); 66 $this->checkRequest($request);
67 $response = $next($request, $response); 67 $response = $next($request, $response);
68 } catch(ApiException $e) { 68 } catch (ApiException $e) {
69 $e->setResponse($response); 69 $e->setResponse($response);
70 $e->setDebug($this->conf->get('dev.debug', false)); 70 $e->setDebug($this->conf->get('dev.debug', false));
71 $response = $e->getApiResponse(); 71 $response = $e->getApiResponse();
@@ -98,7 +98,8 @@ class ApiMiddleware
98 * 98 *
99 * @throws ApiAuthorizationException The token couldn't be validated. 99 * @throws ApiAuthorizationException The token couldn't be validated.
100 */ 100 */
101 protected function checkToken($request) { 101 protected function checkToken($request)
102 {
102 if (! $request->hasHeader('Authorization')) { 103 if (! $request->hasHeader('Authorization')) {
103 throw new ApiAuthorizationException('JWT token not provided'); 104 throw new ApiAuthorizationException('JWT token not provided');
104 } 105 }
diff --git a/application/api/controllers/ApiController.php b/application/api/controllers/ApiController.php
index 3be85b98..9edefcf6 100644
--- a/application/api/controllers/ApiController.php
+++ b/application/api/controllers/ApiController.php
@@ -41,7 +41,7 @@ abstract class ApiController
41 41
42 /** 42 /**
43 * ApiController constructor. 43 * ApiController constructor.
44 * 44 *
45 * Note: enabling debug mode displays JSON with readable formatting. 45 * Note: enabling debug mode displays JSON with readable formatting.
46 * 46 *
47 * @param Container $ci Slim container. 47 * @param Container $ci Slim container.
diff --git a/application/api/controllers/History.php b/application/api/controllers/History.php
index 5cc453bf..4582e8b2 100644
--- a/application/api/controllers/History.php
+++ b/application/api/controllers/History.php
@@ -35,8 +35,7 @@ class History extends ApiController
35 $offset = $request->getParam('offset'); 35 $offset = $request->getParam('offset');
36 if (empty($offset)) { 36 if (empty($offset)) {
37 $offset = 0; 37 $offset = 0;
38 } 38 } elseif (ctype_digit($offset)) {
39 elseif (ctype_digit($offset)) {
40 $offset = (int) $offset; 39 $offset = (int) $offset;
41 } else { 40 } else {
42 throw new ApiBadParametersException('Invalid offset'); 41 throw new ApiBadParametersException('Invalid offset');
diff --git a/application/api/controllers/Info.php b/application/api/controllers/Info.php
index 25433f72..f37dcae5 100644
--- a/application/api/controllers/Info.php
+++ b/application/api/controllers/Info.php
@@ -7,7 +7,7 @@ use Slim\Http\Response;
7 7
8/** 8/**
9 * Class Info 9 * Class Info
10 * 10 *
11 * REST API Controller: /info 11 * REST API Controller: /info
12 * 12 *
13 * @package Api\Controllers 13 * @package Api\Controllers
@@ -17,7 +17,7 @@ class Info extends ApiController
17{ 17{
18 /** 18 /**
19 * Service providing various information about Shaarli instance. 19 * Service providing various information about Shaarli instance.
20 * 20 *
21 * @param Request $request Slim request. 21 * @param Request $request Slim request.
22 * @param Response $response Slim response. 22 * @param Response $response Slim response.
23 * 23 *
diff --git a/application/api/exceptions/ApiException.php b/application/api/exceptions/ApiException.php
index c8490e0c..d6b66323 100644
--- a/application/api/exceptions/ApiException.php
+++ b/application/api/exceptions/ApiException.php
@@ -10,7 +10,8 @@ use Slim\Http\Response;
10 * Parent Exception related to the API, able to generate a valid Response (ResponseInterface). 10 * Parent Exception related to the API, able to generate a valid Response (ResponseInterface).
11 * Also can include various information in debug mode. 11 * Also can include various information in debug mode.
12 */ 12 */
13abstract class ApiException extends \Exception { 13abstract class ApiException extends \Exception
14{
14 15
15 /** 16 /**
16 * @var Response instance from Slim. 17 * @var Response instance from Slim.
@@ -27,7 +28,7 @@ abstract class ApiException extends \Exception {
27 * 28 *
28 * @return Response Final response to give. 29 * @return Response Final response to give.
29 */ 30 */
30 public abstract function getApiResponse(); 31 abstract public function getApiResponse();
31 32
32 /** 33 /**
33 * Creates ApiResponse body. 34 * Creates ApiResponse body.
@@ -36,7 +37,8 @@ abstract class ApiException extends \Exception {
36 * 37 *
37 * @return array|string response body 38 * @return array|string response body
38 */ 39 */
39 protected function getApiResponseBody() { 40 protected function getApiResponseBody()
41 {
40 if ($this->debug !== true) { 42 if ($this->debug !== true) {
41 return $this->getMessage(); 43 return $this->getMessage();
42 } 44 }
diff --git a/application/api/exceptions/ApiLinkNotFoundException.php b/application/api/exceptions/ApiLinkNotFoundException.php
index de7e14f5..c727f4f0 100644
--- a/application/api/exceptions/ApiLinkNotFoundException.php
+++ b/application/api/exceptions/ApiLinkNotFoundException.php
@@ -2,7 +2,6 @@
2 2
3namespace Shaarli\Api\Exceptions; 3namespace Shaarli\Api\Exceptions;
4 4
5
6use Slim\Http\Response; 5use Slim\Http\Response;
7 6
8/** 7/**
diff --git a/application/api/exceptions/ApiTagNotFoundException.php b/application/api/exceptions/ApiTagNotFoundException.php
index eed5afa5..eee152fe 100644
--- a/application/api/exceptions/ApiTagNotFoundException.php
+++ b/application/api/exceptions/ApiTagNotFoundException.php
@@ -2,7 +2,6 @@
2 2
3namespace Shaarli\Api\Exceptions; 3namespace Shaarli\Api\Exceptions;
4 4
5
6use Slim\Http\Response; 5use Slim\Http\Response;
7 6
8/** 7/**
diff --git a/application/config/ConfigPhp.php b/application/config/ConfigPhp.php
index 8add8bcd..9625fe1a 100644
--- a/application/config/ConfigPhp.php
+++ b/application/config/ConfigPhp.php
@@ -104,12 +104,20 @@ class ConfigPhp implements ConfigIO
104 104
105 // Store all $conf['config'] 105 // Store all $conf['config']
106 foreach ($conf['config'] as $key => $value) { 106 foreach ($conf['config'] as $key => $value) {
107 $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL; 107 $configStr .= '$GLOBALS[\'config\'][\''
108 . $key
109 .'\'] = '
110 .var_export($conf['config'][$key], true).';'
111 . PHP_EOL;
108 } 112 }
109 113
110 if (isset($conf['plugins'])) { 114 if (isset($conf['plugins'])) {
111 foreach ($conf['plugins'] as $key => $value) { 115 foreach ($conf['plugins'] as $key => $value) {
112 $configStr .= '$GLOBALS[\'plugins\'][\''. $key .'\'] = '.var_export($conf['plugins'][$key], true).';'. PHP_EOL; 116 $configStr .= '$GLOBALS[\'plugins\'][\''
117 . $key
118 .'\'] = '
119 .var_export($conf['plugins'][$key], true).';'
120 . PHP_EOL;
113 } 121 }
114 } 122 }
115 123
diff --git a/application/config/ConfigPlugin.php b/application/config/ConfigPlugin.php
index b3d9752b..dbb24937 100644
--- a/application/config/ConfigPlugin.php
+++ b/application/config/ConfigPlugin.php
@@ -34,8 +34,7 @@ function save_plugin_config($formData)
34 // If there is no order, it means a disabled plugin has been enabled. 34 // If there is no order, it means a disabled plugin has been enabled.
35 if (isset($formData['order_' . $key])) { 35 if (isset($formData['order_' . $key])) {
36 $plugins[(int) $formData['order_' . $key]] = $key; 36 $plugins[(int) $formData['order_' . $key]] = $key;
37 } 37 } else {
38 else {
39 $newEnabledPlugins[] = $key; 38 $newEnabledPlugins[] = $key;
40 } 39 }
41 } 40 }
diff --git a/application/security/LoginManager.php b/application/security/LoginManager.php
index d6784d6d..0f315483 100644
--- a/application/security/LoginManager.php
+++ b/application/security/LoginManager.php
@@ -95,7 +95,6 @@ class LoginManager
95 // The user client has a valid stay-signed-in cookie 95 // The user client has a valid stay-signed-in cookie
96 // Session information is updated with the current client information 96 // Session information is updated with the current client information
97 $this->sessionManager->storeLoginInfo($clientIpId); 97 $this->sessionManager->storeLoginInfo($clientIpId);
98
99 } elseif ($this->sessionManager->hasSessionExpired() 98 } elseif ($this->sessionManager->hasSessionExpired()
100 || $this->sessionManager->hasClientIpChanged($clientIpId) 99 || $this->sessionManager->hasClientIpChanged($clientIpId)
101 ) { 100 ) {