diff options
Diffstat (limited to 'application/bookmark')
-rw-r--r-- | application/bookmark/Bookmark.php | 25 | ||||
-rw-r--r-- | application/bookmark/BookmarkFileService.php | 38 | ||||
-rw-r--r-- | application/bookmark/BookmarkFilter.php | 2 | ||||
-rw-r--r-- | application/bookmark/BookmarkIO.php | 10 | ||||
-rw-r--r-- | application/bookmark/BookmarkInitializer.php | 9 | ||||
-rw-r--r-- | application/bookmark/BookmarkServiceInterface.php | 1 | ||||
-rw-r--r-- | application/bookmark/LinkUtils.php | 108 | ||||
-rw-r--r-- | application/bookmark/exception/DatastoreNotInitializedException.php | 10 |
8 files changed, 62 insertions, 141 deletions
diff --git a/application/bookmark/Bookmark.php b/application/bookmark/Bookmark.php index f9b21d3d..1beb8be2 100644 --- a/application/bookmark/Bookmark.php +++ b/application/bookmark/Bookmark.php | |||
@@ -3,6 +3,7 @@ | |||
3 | namespace Shaarli\Bookmark; | 3 | namespace Shaarli\Bookmark; |
4 | 4 | ||
5 | use DateTime; | 5 | use DateTime; |
6 | use DateTimeInterface; | ||
6 | use Shaarli\Bookmark\Exception\InvalidBookmarkException; | 7 | use Shaarli\Bookmark\Exception\InvalidBookmarkException; |
7 | 8 | ||
8 | /** | 9 | /** |
@@ -36,16 +37,16 @@ class Bookmark | |||
36 | /** @var array List of bookmark's tags */ | 37 | /** @var array List of bookmark's tags */ |
37 | protected $tags; | 38 | protected $tags; |
38 | 39 | ||
39 | /** @var string Thumbnail's URL - false if no thumbnail could be found */ | 40 | /** @var string|bool|null Thumbnail's URL - initialized at null, false if no thumbnail could be found */ |
40 | protected $thumbnail; | 41 | protected $thumbnail; |
41 | 42 | ||
42 | /** @var bool Set to true if the bookmark is set as sticky */ | 43 | /** @var bool Set to true if the bookmark is set as sticky */ |
43 | protected $sticky; | 44 | protected $sticky; |
44 | 45 | ||
45 | /** @var DateTime Creation datetime */ | 46 | /** @var DateTimeInterface Creation datetime */ |
46 | protected $created; | 47 | protected $created; |
47 | 48 | ||
48 | /** @var DateTime Update datetime */ | 49 | /** @var DateTimeInterface datetime */ |
49 | protected $updated; | 50 | protected $updated; |
50 | 51 | ||
51 | /** @var bool True if the bookmark can only be seen while logged in */ | 52 | /** @var bool True if the bookmark can only be seen while logged in */ |
@@ -100,12 +101,12 @@ class Bookmark | |||
100 | || ! is_int($this->id) | 101 | || ! is_int($this->id) |
101 | || empty($this->shortUrl) | 102 | || empty($this->shortUrl) |
102 | || empty($this->created) | 103 | || empty($this->created) |
103 | || ! $this->created instanceof DateTime | 104 | || ! $this->created instanceof DateTimeInterface |
104 | ) { | 105 | ) { |
105 | throw new InvalidBookmarkException($this); | 106 | throw new InvalidBookmarkException($this); |
106 | } | 107 | } |
107 | if (empty($this->url)) { | 108 | if (empty($this->url)) { |
108 | $this->url = '?'. $this->shortUrl; | 109 | $this->url = '/shaare/'. $this->shortUrl; |
109 | } | 110 | } |
110 | if (empty($this->title)) { | 111 | if (empty($this->title)) { |
111 | $this->title = $this->url; | 112 | $this->title = $this->url; |
@@ -188,7 +189,7 @@ class Bookmark | |||
188 | /** | 189 | /** |
189 | * Get the Created. | 190 | * Get the Created. |
190 | * | 191 | * |
191 | * @return DateTime | 192 | * @return DateTimeInterface |
192 | */ | 193 | */ |
193 | public function getCreated() | 194 | public function getCreated() |
194 | { | 195 | { |
@@ -198,7 +199,7 @@ class Bookmark | |||
198 | /** | 199 | /** |
199 | * Get the Updated. | 200 | * Get the Updated. |
200 | * | 201 | * |
201 | * @return DateTime | 202 | * @return DateTimeInterface |
202 | */ | 203 | */ |
203 | public function getUpdated() | 204 | public function getUpdated() |
204 | { | 205 | { |
@@ -270,7 +271,7 @@ class Bookmark | |||
270 | * Set the Created. | 271 | * Set the Created. |
271 | * Note: you shouldn't set this manually except for special cases (like bookmark import) | 272 | * Note: you shouldn't set this manually except for special cases (like bookmark import) |
272 | * | 273 | * |
273 | * @param DateTime $created | 274 | * @param DateTimeInterface $created |
274 | * | 275 | * |
275 | * @return Bookmark | 276 | * @return Bookmark |
276 | */ | 277 | */ |
@@ -284,7 +285,7 @@ class Bookmark | |||
284 | /** | 285 | /** |
285 | * Set the Updated. | 286 | * Set the Updated. |
286 | * | 287 | * |
287 | * @param DateTime $updated | 288 | * @param DateTimeInterface $updated |
288 | * | 289 | * |
289 | * @return Bookmark | 290 | * @return Bookmark |
290 | */ | 291 | */ |
@@ -346,7 +347,7 @@ class Bookmark | |||
346 | /** | 347 | /** |
347 | * Get the Thumbnail. | 348 | * Get the Thumbnail. |
348 | * | 349 | * |
349 | * @return string|bool | 350 | * @return string|bool|null Thumbnail's URL - initialized at null, false if no thumbnail could be found |
350 | */ | 351 | */ |
351 | public function getThumbnail() | 352 | public function getThumbnail() |
352 | { | 353 | { |
@@ -356,7 +357,7 @@ class Bookmark | |||
356 | /** | 357 | /** |
357 | * Set the Thumbnail. | 358 | * Set the Thumbnail. |
358 | * | 359 | * |
359 | * @param string|bool $thumbnail | 360 | * @param string|bool $thumbnail Thumbnail's URL - false if no thumbnail could be found |
360 | * | 361 | * |
361 | * @return Bookmark | 362 | * @return Bookmark |
362 | */ | 363 | */ |
@@ -405,7 +406,7 @@ class Bookmark | |||
405 | public function isNote() | 406 | public function isNote() |
406 | { | 407 | { |
407 | // We check empty value to get a valid result if the link has not been saved yet | 408 | // We check empty value to get a valid result if the link has not been saved yet |
408 | return empty($this->url) || $this->url[0] === '?'; | 409 | return empty($this->url) || startsWith($this->url, '/shaare/') || $this->url[0] === '?'; |
409 | } | 410 | } |
410 | 411 | ||
411 | /** | 412 | /** |
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php index 9c59e139..b3a90ed4 100644 --- a/application/bookmark/BookmarkFileService.php +++ b/application/bookmark/BookmarkFileService.php | |||
@@ -6,12 +6,14 @@ namespace Shaarli\Bookmark; | |||
6 | 6 | ||
7 | use Exception; | 7 | use Exception; |
8 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; | 8 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; |
9 | use Shaarli\Bookmark\Exception\DatastoreNotInitializedException; | ||
9 | use Shaarli\Bookmark\Exception\EmptyDataStoreException; | 10 | use Shaarli\Bookmark\Exception\EmptyDataStoreException; |
10 | use Shaarli\Config\ConfigManager; | 11 | use Shaarli\Config\ConfigManager; |
11 | use Shaarli\Formatter\BookmarkMarkdownFormatter; | 12 | use Shaarli\Formatter\BookmarkMarkdownFormatter; |
12 | use Shaarli\History; | 13 | use Shaarli\History; |
13 | use Shaarli\Legacy\LegacyLinkDB; | 14 | use Shaarli\Legacy\LegacyLinkDB; |
14 | use Shaarli\Legacy\LegacyUpdater; | 15 | use Shaarli\Legacy\LegacyUpdater; |
16 | use Shaarli\Render\PageCacheManager; | ||
15 | use Shaarli\Updater\UpdaterUtils; | 17 | use Shaarli\Updater\UpdaterUtils; |
16 | 18 | ||
17 | /** | 19 | /** |
@@ -39,6 +41,9 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
39 | /** @var History instance */ | 41 | /** @var History instance */ |
40 | protected $history; | 42 | protected $history; |
41 | 43 | ||
44 | /** @var PageCacheManager instance */ | ||
45 | protected $pageCacheManager; | ||
46 | |||
42 | /** @var bool true for logged in users. Default value to retrieve private bookmarks. */ | 47 | /** @var bool true for logged in users. Default value to retrieve private bookmarks. */ |
43 | protected $isLoggedIn; | 48 | protected $isLoggedIn; |
44 | 49 | ||
@@ -49,6 +54,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
49 | { | 54 | { |
50 | $this->conf = $conf; | 55 | $this->conf = $conf; |
51 | $this->history = $history; | 56 | $this->history = $history; |
57 | $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache'), $isLoggedIn); | ||
52 | $this->bookmarksIO = new BookmarkIO($this->conf); | 58 | $this->bookmarksIO = new BookmarkIO($this->conf); |
53 | $this->isLoggedIn = $isLoggedIn; | 59 | $this->isLoggedIn = $isLoggedIn; |
54 | 60 | ||
@@ -57,10 +63,16 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
57 | } else { | 63 | } else { |
58 | try { | 64 | try { |
59 | $this->bookmarks = $this->bookmarksIO->read(); | 65 | $this->bookmarks = $this->bookmarksIO->read(); |
60 | } catch (EmptyDataStoreException $e) { | 66 | } catch (EmptyDataStoreException|DatastoreNotInitializedException $e) { |
61 | $this->bookmarks = new BookmarkArray(); | 67 | $this->bookmarks = new BookmarkArray(); |
62 | if ($isLoggedIn) { | 68 | |
63 | $this->save(); | 69 | if ($this->isLoggedIn) { |
70 | // Datastore file does not exists, we initialize it with default bookmarks. | ||
71 | if ($e instanceof DatastoreNotInitializedException) { | ||
72 | $this->initialize(); | ||
73 | } else { | ||
74 | $this->save(); | ||
75 | } | ||
64 | } | 76 | } |
65 | } | 77 | } |
66 | 78 | ||
@@ -88,7 +100,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
88 | throw new Exception('Not authorized'); | 100 | throw new Exception('Not authorized'); |
89 | } | 101 | } |
90 | 102 | ||
91 | return $bookmark; | 103 | return $first; |
92 | } | 104 | } |
93 | 105 | ||
94 | /** | 106 | /** |
@@ -149,7 +161,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
149 | */ | 161 | */ |
150 | public function set($bookmark, $save = true) | 162 | public function set($bookmark, $save = true) |
151 | { | 163 | { |
152 | if ($this->isLoggedIn !== true) { | 164 | if (true !== $this->isLoggedIn) { |
153 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 165 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
154 | } | 166 | } |
155 | if (! $bookmark instanceof Bookmark) { | 167 | if (! $bookmark instanceof Bookmark) { |
@@ -174,7 +186,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
174 | */ | 186 | */ |
175 | public function add($bookmark, $save = true) | 187 | public function add($bookmark, $save = true) |
176 | { | 188 | { |
177 | if ($this->isLoggedIn !== true) { | 189 | if (true !== $this->isLoggedIn) { |
178 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 190 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
179 | } | 191 | } |
180 | if (! $bookmark instanceof Bookmark) { | 192 | if (! $bookmark instanceof Bookmark) { |
@@ -199,7 +211,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
199 | */ | 211 | */ |
200 | public function addOrSet($bookmark, $save = true) | 212 | public function addOrSet($bookmark, $save = true) |
201 | { | 213 | { |
202 | if ($this->isLoggedIn !== true) { | 214 | if (true !== $this->isLoggedIn) { |
203 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 215 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
204 | } | 216 | } |
205 | if (! $bookmark instanceof Bookmark) { | 217 | if (! $bookmark instanceof Bookmark) { |
@@ -216,7 +228,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
216 | */ | 228 | */ |
217 | public function remove($bookmark, $save = true) | 229 | public function remove($bookmark, $save = true) |
218 | { | 230 | { |
219 | if ($this->isLoggedIn !== true) { | 231 | if (true !== $this->isLoggedIn) { |
220 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 232 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
221 | } | 233 | } |
222 | if (! $bookmark instanceof Bookmark) { | 234 | if (! $bookmark instanceof Bookmark) { |
@@ -269,13 +281,14 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
269 | */ | 281 | */ |
270 | public function save() | 282 | public function save() |
271 | { | 283 | { |
272 | if (!$this->isLoggedIn) { | 284 | if (true !== $this->isLoggedIn) { |
273 | // TODO: raise an Exception instead | 285 | // TODO: raise an Exception instead |
274 | die('You are not authorized to change the database.'); | 286 | die('You are not authorized to change the database.'); |
275 | } | 287 | } |
288 | |||
276 | $this->bookmarks->reorder(); | 289 | $this->bookmarks->reorder(); |
277 | $this->bookmarksIO->write($this->bookmarks); | 290 | $this->bookmarksIO->write($this->bookmarks); |
278 | invalidateCaches($this->conf->get('resource.page_cache')); | 291 | $this->pageCacheManager->invalidateCaches(); |
279 | } | 292 | } |
280 | 293 | ||
281 | /** | 294 | /** |
@@ -291,6 +304,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
291 | if (empty($tag) | 304 | if (empty($tag) |
292 | || (! $this->isLoggedIn && startsWith($tag, '.')) | 305 | || (! $this->isLoggedIn && startsWith($tag, '.')) |
293 | || $tag === BookmarkMarkdownFormatter::NO_MD_TAG | 306 | || $tag === BookmarkMarkdownFormatter::NO_MD_TAG |
307 | || in_array($tag, $filteringTags, true) | ||
294 | ) { | 308 | ) { |
295 | continue; | 309 | continue; |
296 | } | 310 | } |
@@ -349,6 +363,10 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
349 | { | 363 | { |
350 | $initializer = new BookmarkInitializer($this); | 364 | $initializer = new BookmarkInitializer($this); |
351 | $initializer->initialize(); | 365 | $initializer->initialize(); |
366 | |||
367 | if (true === $this->isLoggedIn) { | ||
368 | $this->save(); | ||
369 | } | ||
352 | } | 370 | } |
353 | 371 | ||
354 | /** | 372 | /** |
diff --git a/application/bookmark/BookmarkFilter.php b/application/bookmark/BookmarkFilter.php index fd556679..797a36b8 100644 --- a/application/bookmark/BookmarkFilter.php +++ b/application/bookmark/BookmarkFilter.php | |||
@@ -436,7 +436,7 @@ class BookmarkFilter | |||
436 | throw new Exception('Invalid date format'); | 436 | throw new Exception('Invalid date format'); |
437 | } | 437 | } |
438 | 438 | ||
439 | $filtered = array(); | 439 | $filtered = []; |
440 | foreach ($this->bookmarks as $key => $l) { | 440 | foreach ($this->bookmarks as $key => $l) { |
441 | if ($l->getCreated()->format('Ymd') == $day) { | 441 | if ($l->getCreated()->format('Ymd') == $day) { |
442 | $filtered[$key] = $l; | 442 | $filtered[$key] = $l; |
diff --git a/application/bookmark/BookmarkIO.php b/application/bookmark/BookmarkIO.php index ae9ffcb4..6bf7f365 100644 --- a/application/bookmark/BookmarkIO.php +++ b/application/bookmark/BookmarkIO.php | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | namespace Shaarli\Bookmark; | 3 | namespace Shaarli\Bookmark; |
4 | 4 | ||
5 | use Shaarli\Bookmark\Exception\DatastoreNotInitializedException; | ||
5 | use Shaarli\Bookmark\Exception\EmptyDataStoreException; | 6 | use Shaarli\Bookmark\Exception\EmptyDataStoreException; |
6 | use Shaarli\Bookmark\Exception\NotWritableDataStoreException; | 7 | use Shaarli\Bookmark\Exception\NotWritableDataStoreException; |
7 | use Shaarli\Config\ConfigManager; | 8 | use Shaarli\Config\ConfigManager; |
@@ -52,13 +53,14 @@ class BookmarkIO | |||
52 | * | 53 | * |
53 | * @return BookmarkArray instance | 54 | * @return BookmarkArray instance |
54 | * | 55 | * |
55 | * @throws NotWritableDataStoreException Data couldn't be loaded | 56 | * @throws NotWritableDataStoreException Data couldn't be loaded |
56 | * @throws EmptyDataStoreException Datastore doesn't exist | 57 | * @throws EmptyDataStoreException Datastore file exists but does not contain any bookmark |
58 | * @throws DatastoreNotInitializedException File does not exists | ||
57 | */ | 59 | */ |
58 | public function read() | 60 | public function read() |
59 | { | 61 | { |
60 | if (! file_exists($this->datastore)) { | 62 | if (! file_exists($this->datastore)) { |
61 | throw new EmptyDataStoreException(); | 63 | throw new DatastoreNotInitializedException(); |
62 | } | 64 | } |
63 | 65 | ||
64 | if (!is_writable($this->datastore)) { | 66 | if (!is_writable($this->datastore)) { |
@@ -102,7 +104,5 @@ class BookmarkIO | |||
102 | $this->datastore, | 104 | $this->datastore, |
103 | self::$phpPrefix.base64_encode(gzdeflate(serialize($links))).self::$phpSuffix | 105 | self::$phpPrefix.base64_encode(gzdeflate(serialize($links))).self::$phpSuffix |
104 | ); | 106 | ); |
105 | |||
106 | invalidateCaches($this->conf->get('resource.page_cache')); | ||
107 | } | 107 | } |
108 | } | 108 | } |
diff --git a/application/bookmark/BookmarkInitializer.php b/application/bookmark/BookmarkInitializer.php index 9eee9a35..cd2d1724 100644 --- a/application/bookmark/BookmarkInitializer.php +++ b/application/bookmark/BookmarkInitializer.php | |||
@@ -6,8 +6,7 @@ namespace Shaarli\Bookmark; | |||
6 | * Class BookmarkInitializer | 6 | * Class BookmarkInitializer |
7 | * | 7 | * |
8 | * This class is used to initialized default bookmarks after a fresh install of Shaarli. | 8 | * This class is used to initialized default bookmarks after a fresh install of Shaarli. |
9 | * It is no longer call when the data store is empty, | 9 | * It should be only called if the datastore file does not exist(users might want to delete the default bookmarks). |
10 | * because user might want to delete default bookmarks after the install. | ||
11 | * | 10 | * |
12 | * To prevent data corruption, it does not overwrite existing bookmarks, | 11 | * To prevent data corruption, it does not overwrite existing bookmarks, |
13 | * even though there should not be any. | 12 | * even though there should not be any. |
@@ -36,11 +35,11 @@ class BookmarkInitializer | |||
36 | { | 35 | { |
37 | $bookmark = new Bookmark(); | 36 | $bookmark = new Bookmark(); |
38 | $bookmark->setTitle(t('My secret stuff... - Pastebin.com')); | 37 | $bookmark->setTitle(t('My secret stuff... - Pastebin.com')); |
39 | $bookmark->setUrl('http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=', []); | 38 | $bookmark->setUrl('http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8='); |
40 | $bookmark->setDescription(t('Shhhh! I\'m a private link only YOU can see. You can delete me too.')); | 39 | $bookmark->setDescription(t('Shhhh! I\'m a private link only YOU can see. You can delete me too.')); |
41 | $bookmark->setTagsString('secretstuff'); | 40 | $bookmark->setTagsString('secretstuff'); |
42 | $bookmark->setPrivate(true); | 41 | $bookmark->setPrivate(true); |
43 | $this->bookmarkService->add($bookmark); | 42 | $this->bookmarkService->add($bookmark, false); |
44 | 43 | ||
45 | $bookmark = new Bookmark(); | 44 | $bookmark = new Bookmark(); |
46 | $bookmark->setTitle(t('The personal, minimalist, super-fast, database free, bookmarking service')); | 45 | $bookmark->setTitle(t('The personal, minimalist, super-fast, database free, bookmarking service')); |
@@ -54,6 +53,6 @@ To learn how to use Shaarli, consult the link "Documentation" at the bottom of t | |||
54 | You use the community supported version of the original Shaarli project, by Sebastien Sauvage.' | 53 | You use the community supported version of the original Shaarli project, by Sebastien Sauvage.' |
55 | )); | 54 | )); |
56 | $bookmark->setTagsString('opensource software'); | 55 | $bookmark->setTagsString('opensource software'); |
57 | $this->bookmarkService->add($bookmark); | 56 | $this->bookmarkService->add($bookmark, false); |
58 | } | 57 | } |
59 | } | 58 | } |
diff --git a/application/bookmark/BookmarkServiceInterface.php b/application/bookmark/BookmarkServiceInterface.php index 7b7a4f09..ce8bd912 100644 --- a/application/bookmark/BookmarkServiceInterface.php +++ b/application/bookmark/BookmarkServiceInterface.php | |||
@@ -6,7 +6,6 @@ namespace Shaarli\Bookmark; | |||
6 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; | 6 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; |
7 | use Shaarli\Bookmark\Exception\NotWritableDataStoreException; | 7 | use Shaarli\Bookmark\Exception\NotWritableDataStoreException; |
8 | use Shaarli\Config\ConfigManager; | 8 | use Shaarli\Config\ConfigManager; |
9 | use Shaarli\Exceptions\IOException; | ||
10 | use Shaarli\History; | 9 | use Shaarli\History; |
11 | 10 | ||
12 | /** | 11 | /** |
diff --git a/application/bookmark/LinkUtils.php b/application/bookmark/LinkUtils.php index 88379430..68914fca 100644 --- a/application/bookmark/LinkUtils.php +++ b/application/bookmark/LinkUtils.php | |||
@@ -3,112 +3,6 @@ | |||
3 | use Shaarli\Bookmark\Bookmark; | 3 | use Shaarli\Bookmark\Bookmark; |
4 | 4 | ||
5 | /** | 5 | /** |
6 | * Get cURL callback function for CURLOPT_WRITEFUNCTION | ||
7 | * | ||
8 | * @param string $charset to extract from the downloaded page (reference) | ||
9 | * @param string $title to extract from the downloaded page (reference) | ||
10 | * @param string $description to extract from the downloaded page (reference) | ||
11 | * @param string $keywords to extract from the downloaded page (reference) | ||
12 | * @param bool $retrieveDescription Automatically tries to retrieve description and keywords from HTML content | ||
13 | * @param string $curlGetInfo Optionally overrides curl_getinfo function | ||
14 | * | ||
15 | * @return Closure | ||
16 | */ | ||
17 | function get_curl_download_callback( | ||
18 | &$charset, | ||
19 | &$title, | ||
20 | &$description, | ||
21 | &$keywords, | ||
22 | $retrieveDescription, | ||
23 | $curlGetInfo = 'curl_getinfo' | ||
24 | ) { | ||
25 | $isRedirected = false; | ||
26 | $currentChunk = 0; | ||
27 | $foundChunk = null; | ||
28 | |||
29 | /** | ||
30 | * cURL callback function for CURLOPT_WRITEFUNCTION (called during the download). | ||
31 | * | ||
32 | * While downloading the remote page, we check that the HTTP code is 200 and content type is 'html/text' | ||
33 | * Then we extract the title and the charset and stop the download when it's done. | ||
34 | * | ||
35 | * @param resource $ch cURL resource | ||
36 | * @param string $data chunk of data being downloaded | ||
37 | * | ||
38 | * @return int|bool length of $data or false if we need to stop the download | ||
39 | */ | ||
40 | return function (&$ch, $data) use ( | ||
41 | $retrieveDescription, | ||
42 | $curlGetInfo, | ||
43 | &$charset, | ||
44 | &$title, | ||
45 | &$description, | ||
46 | &$keywords, | ||
47 | &$isRedirected, | ||
48 | &$currentChunk, | ||
49 | &$foundChunk | ||
50 | ) { | ||
51 | $currentChunk++; | ||
52 | $responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE); | ||
53 | if (!empty($responseCode) && in_array($responseCode, [301, 302])) { | ||
54 | $isRedirected = true; | ||
55 | return strlen($data); | ||
56 | } | ||
57 | if (!empty($responseCode) && $responseCode !== 200) { | ||
58 | return false; | ||
59 | } | ||
60 | // After a redirection, the content type will keep the previous request value | ||
61 | // until it finds the next content-type header. | ||
62 | if (! $isRedirected || strpos(strtolower($data), 'content-type') !== false) { | ||
63 | $contentType = $curlGetInfo($ch, CURLINFO_CONTENT_TYPE); | ||
64 | } | ||
65 | if (!empty($contentType) && strpos($contentType, 'text/html') === false) { | ||
66 | return false; | ||
67 | } | ||
68 | if (!empty($contentType) && empty($charset)) { | ||
69 | $charset = header_extract_charset($contentType); | ||
70 | } | ||
71 | if (empty($charset)) { | ||
72 | $charset = html_extract_charset($data); | ||
73 | } | ||
74 | if (empty($title)) { | ||
75 | $title = html_extract_title($data); | ||
76 | $foundChunk = ! empty($title) ? $currentChunk : $foundChunk; | ||
77 | } | ||
78 | if ($retrieveDescription && empty($description)) { | ||
79 | $description = html_extract_tag('description', $data); | ||
80 | $foundChunk = ! empty($description) ? $currentChunk : $foundChunk; | ||
81 | } | ||
82 | if ($retrieveDescription && empty($keywords)) { | ||
83 | $keywords = html_extract_tag('keywords', $data); | ||
84 | if (! empty($keywords)) { | ||
85 | $foundChunk = $currentChunk; | ||
86 | // Keywords use the format tag1, tag2 multiple words, tag | ||
87 | // So we format them to match Shaarli's separator and glue multiple words with '-' | ||
88 | $keywords = implode(' ', array_map(function($keyword) { | ||
89 | return implode('-', preg_split('/\s+/', trim($keyword))); | ||
90 | }, explode(',', $keywords))); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | // We got everything we want, stop the download. | ||
95 | // If we already found either the title, description or keywords, | ||
96 | // it's highly unlikely that we'll found the other metas further than | ||
97 | // in the same chunk of data or the next one. So we also stop the download after that. | ||
98 | if ((!empty($responseCode) && !empty($contentType) && !empty($charset)) && $foundChunk !== null | ||
99 | && (! $retrieveDescription | ||
100 | || $foundChunk < $currentChunk | ||
101 | || (!empty($title) && !empty($description) && !empty($keywords)) | ||
102 | ) | ||
103 | ) { | ||
104 | return false; | ||
105 | } | ||
106 | |||
107 | return strlen($data); | ||
108 | }; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Extract title from an HTML document. | 6 | * Extract title from an HTML document. |
113 | * | 7 | * |
114 | * @param string $html HTML content where to look for a title. | 8 | * @param string $html HTML content where to look for a title. |
@@ -220,7 +114,7 @@ function hashtag_autolink($description, $indexUrl = '') | |||
220 | * \p{Mn} - any non marking space (accents, umlauts, etc) | 114 | * \p{Mn} - any non marking space (accents, umlauts, etc) |
221 | */ | 115 | */ |
222 | $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui'; | 116 | $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui'; |
223 | $replacement = '$1<a href="'. $indexUrl .'?addtag=$2" title="Hashtag $2">#$2</a>'; | 117 | $replacement = '$1<a href="'. $indexUrl .'./add-tag/$2" title="Hashtag $2">#$2</a>'; |
224 | return preg_replace($regex, $replacement, $description); | 118 | return preg_replace($regex, $replacement, $description); |
225 | } | 119 | } |
226 | 120 | ||
diff --git a/application/bookmark/exception/DatastoreNotInitializedException.php b/application/bookmark/exception/DatastoreNotInitializedException.php new file mode 100644 index 00000000..f495049d --- /dev/null +++ b/application/bookmark/exception/DatastoreNotInitializedException.php | |||
@@ -0,0 +1,10 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Shaarli\Bookmark\Exception; | ||
6 | |||
7 | class DatastoreNotInitializedException extends \Exception | ||
8 | { | ||
9 | |||
10 | } | ||