]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - application/bookmark/BookmarkIO.php
Apply PHP Code Beautifier on source code for linter automatic fixes
[github/shaarli/Shaarli.git] / application / bookmark / BookmarkIO.php
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Shaarli\Bookmark;
6
7 use malkusch\lock\mutex\Mutex;
8 use malkusch\lock\mutex\NoMutex;
9 use Shaarli\Bookmark\Exception\DatastoreNotInitializedException;
10 use Shaarli\Bookmark\Exception\EmptyDataStoreException;
11 use Shaarli\Bookmark\Exception\NotWritableDataStoreException;
12 use Shaarli\Config\ConfigManager;
13
14 /**
15 * Class BookmarkIO
16 *
17 * This class performs read/write operation to the file data store.
18 * Used by BookmarkFileService.
19 *
20 * @package Shaarli\Bookmark
21 */
22 class BookmarkIO
23 {
24 /**
25 * @var string Datastore file path
26 */
27 protected $datastore;
28
29 /**
30 * @var ConfigManager instance
31 */
32 protected $conf;
33
34
35 /** @var Mutex */
36 protected $mutex;
37
38 /**
39 * string Datastore PHP prefix
40 */
41 protected static $phpPrefix = '<?php /* ';
42 /**
43 * string Datastore PHP suffix
44 */
45 protected static $phpSuffix = ' */ ?>';
46
47 /**
48 * LinksIO constructor.
49 *
50 * @param ConfigManager $conf instance
51 */
52 public function __construct(ConfigManager $conf, Mutex $mutex = null)
53 {
54 if ($mutex === null) {
55 // This should only happen with legacy classes
56 $mutex = new NoMutex();
57 }
58 $this->conf = $conf;
59 $this->datastore = $conf->get('resource.datastore');
60 $this->mutex = $mutex;
61 }
62
63 /**
64 * Reads database from disk to memory
65 *
66 * @return Bookmark[]
67 *
68 * @throws NotWritableDataStoreException Data couldn't be loaded
69 * @throws EmptyDataStoreException Datastore file exists but does not contain any bookmark
70 * @throws DatastoreNotInitializedException File does not exists
71 */
72 public function read()
73 {
74 if (! file_exists($this->datastore)) {
75 throw new DatastoreNotInitializedException();
76 }
77
78 if (!is_writable($this->datastore)) {
79 throw new NotWritableDataStoreException($this->datastore);
80 }
81
82 $content = null;
83 $this->mutex->synchronized(function () use (&$content) {
84 $content = file_get_contents($this->datastore);
85 });
86
87 // Note that gzinflate is faster than gzuncompress.
88 // See: http://www.php.net/manual/en/function.gzdeflate.php#96439
89 $links = unserialize(gzinflate(base64_decode(
90 substr($content, strlen(self::$phpPrefix), -strlen(self::$phpSuffix))
91 )));
92
93 if (empty($links)) {
94 if (filesize($this->datastore) > 100) {
95 throw new NotWritableDataStoreException($this->datastore);
96 }
97 throw new EmptyDataStoreException();
98 }
99
100 return $links;
101 }
102
103 /**
104 * Saves the database from memory to disk
105 *
106 * @param Bookmark[] $links
107 *
108 * @throws NotWritableDataStoreException the datastore is not writable
109 */
110 public function write($links)
111 {
112 if (is_file($this->datastore) && !is_writeable($this->datastore)) {
113 // The datastore exists but is not writeable
114 throw new NotWritableDataStoreException($this->datastore);
115 } elseif (!is_file($this->datastore) && !is_writeable(dirname($this->datastore))) {
116 // The datastore does not exist and its parent directory is not writeable
117 throw new NotWritableDataStoreException(dirname($this->datastore));
118 }
119
120 $data = self::$phpPrefix . base64_encode(gzdeflate(serialize($links))) . self::$phpSuffix;
121
122 $this->mutex->synchronized(function () use ($data) {
123 file_put_contents(
124 $this->datastore,
125 $data
126 );
127 });
128 }
129 }