diff options
author | ArthurHoaro <arthur@hoa.ro> | 2017-01-16 12:30:18 +0100 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2017-03-21 20:16:26 +0100 |
commit | b2306b0c783365e3f8110ae25bc93f2630b8b2c8 (patch) | |
tree | 746c41d42d3230e05839fa2631e78b9e283b33ad /application | |
parent | c4c655d9bfe68a914898d76bb9c479eea1b04f72 (diff) | |
download | Shaarli-b2306b0c783365e3f8110ae25bc93f2630b8b2c8.tar.gz Shaarli-b2306b0c783365e3f8110ae25bc93f2630b8b2c8.tar.zst Shaarli-b2306b0c783365e3f8110ae25bc93f2630b8b2c8.zip |
Move database read/write to FileUtils class + additional unit tests
Diffstat (limited to 'application')
-rw-r--r-- | application/FileUtils.php | 75 | ||||
-rw-r--r-- | application/LinkDB.php | 31 | ||||
-rw-r--r-- | application/exceptions/IOException.php | 22 |
3 files changed, 89 insertions, 39 deletions
diff --git a/application/FileUtils.php b/application/FileUtils.php index 6cac9825..b8ad8970 100644 --- a/application/FileUtils.php +++ b/application/FileUtils.php | |||
@@ -1,21 +1,76 @@ | |||
1 | <?php | 1 | <?php |
2 | |||
3 | require_once 'exceptions/IOException.php'; | ||
4 | |||
2 | /** | 5 | /** |
3 | * Exception class thrown when a filesystem access failure happens | 6 | * Class FileUtils |
7 | * | ||
8 | * Utility class for file manipulation. | ||
4 | */ | 9 | */ |
5 | class IOException extends Exception | 10 | class FileUtils |
6 | { | 11 | { |
7 | private $path; | 12 | /** |
13 | * @var string | ||
14 | */ | ||
15 | protected static $phpPrefix = '<?php /* '; | ||
16 | |||
17 | /** | ||
18 | * @var string | ||
19 | */ | ||
20 | protected static $phpSuffix = ' */ ?>'; | ||
8 | 21 | ||
9 | /** | 22 | /** |
10 | * Construct a new IOException | 23 | * Write data into a file (Shaarli database format). |
24 | * The data is stored in a PHP file, as a comment, in compressed base64 format. | ||
25 | * | ||
26 | * The file will be created if it doesn't exist. | ||
27 | * | ||
28 | * @param string $file File path. | ||
29 | * @param string $content Content to write. | ||
30 | * | ||
31 | * @return int|bool Number of bytes written or false if it fails. | ||
11 | * | 32 | * |
12 | * @param string $path path to the resource that cannot be accessed | 33 | * @throws IOException The destination file can't be written. |
13 | * @param string $message Custom exception message. | ||
14 | */ | 34 | */ |
15 | public function __construct($path, $message = '') | 35 | public static function writeFlatDB($file, $content) |
16 | { | 36 | { |
17 | $this->path = $path; | 37 | if (is_file($file) && !is_writeable($file)) { |
18 | $this->message = empty($message) ? 'Error accessing' : $message; | 38 | // The datastore exists but is not writeable |
19 | $this->message .= PHP_EOL . $this->path; | 39 | throw new IOException($file); |
40 | } else if (!is_file($file) && !is_writeable(dirname($file))) { | ||
41 | // The datastore does not exist and its parent directory is not writeable | ||
42 | throw new IOException(dirname($file)); | ||
43 | } | ||
44 | |||
45 | return file_put_contents( | ||
46 | $file, | ||
47 | self::$phpPrefix.base64_encode(gzdeflate(serialize($content))).self::$phpSuffix | ||
48 | ); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * Read data from a file containing Shaarli database format content. | ||
53 | * If the file isn't readable or doesn't exists, default data will be returned. | ||
54 | * | ||
55 | * @param string $file File path. | ||
56 | * @param mixed $default The default value to return if the file isn't readable. | ||
57 | * | ||
58 | * @return mixed The content unserialized, or default if the file isn't readable, or false if it fails. | ||
59 | */ | ||
60 | public static function readFlatDB($file, $default = null) | ||
61 | { | ||
62 | // Note that gzinflate is faster than gzuncompress. | ||
63 | // See: http://www.php.net/manual/en/function.gzdeflate.php#96439 | ||
64 | if (is_readable($file)) { | ||
65 | return unserialize( | ||
66 | gzinflate( | ||
67 | base64_decode( | ||
68 | substr(file_get_contents($file), strlen(self::$phpPrefix), -strlen(self::$phpSuffix)) | ||
69 | ) | ||
70 | ) | ||
71 | ); | ||
72 | } | ||
73 | |||
74 | return $default; | ||
20 | } | 75 | } |
21 | } | 76 | } |
diff --git a/application/LinkDB.php b/application/LinkDB.php index 4cee2af9..2fb15040 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php | |||
@@ -50,12 +50,6 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
50 | // Link date storage format | 50 | // Link date storage format |
51 | const LINK_DATE_FORMAT = 'Ymd_His'; | 51 | const LINK_DATE_FORMAT = 'Ymd_His'; |
52 | 52 | ||
53 | // Datastore PHP prefix | ||
54 | protected static $phpPrefix = '<?php /* '; | ||
55 | |||
56 | // Datastore PHP suffix | ||
57 | protected static $phpSuffix = ' */ ?>'; | ||
58 | |||
59 | // List of links (associative array) | 53 | // List of links (associative array) |
60 | // - key: link date (e.g. "20110823_124546"), | 54 | // - key: link date (e.g. "20110823_124546"), |
61 | // - value: associative array (keys: title, description...) | 55 | // - value: associative array (keys: title, description...) |
@@ -295,16 +289,7 @@ You use the community supported version of the original Shaarli project, by Seba | |||
295 | return; | 289 | return; |
296 | } | 290 | } |
297 | 291 | ||
298 | // Read data | 292 | $this->links = FileUtils::readFlatDB($this->datastore, []); |
299 | // Note that gzinflate is faster than gzuncompress. | ||
300 | // See: http://www.php.net/manual/en/function.gzdeflate.php#96439 | ||
301 | $this->links = array(); | ||
302 | |||
303 | if (file_exists($this->datastore)) { | ||
304 | $this->links = unserialize(gzinflate(base64_decode( | ||
305 | substr(file_get_contents($this->datastore), | ||
306 | strlen(self::$phpPrefix), -strlen(self::$phpSuffix))))); | ||
307 | } | ||
308 | 293 | ||
309 | $toremove = array(); | 294 | $toremove = array(); |
310 | foreach ($this->links as $key => &$link) { | 295 | foreach ($this->links as $key => &$link) { |
@@ -361,19 +346,7 @@ You use the community supported version of the original Shaarli project, by Seba | |||
361 | */ | 346 | */ |
362 | private function write() | 347 | private function write() |
363 | { | 348 | { |
364 | if (is_file($this->datastore) && !is_writeable($this->datastore)) { | 349 | FileUtils::writeFlatDB($this->datastore, $this->links); |
365 | // The datastore exists but is not writeable | ||
366 | throw new IOException($this->datastore); | ||
367 | } else if (!is_file($this->datastore) && !is_writeable(dirname($this->datastore))) { | ||
368 | // The datastore does not exist and its parent directory is not writeable | ||
369 | throw new IOException(dirname($this->datastore)); | ||
370 | } | ||
371 | |||
372 | file_put_contents( | ||
373 | $this->datastore, | ||
374 | self::$phpPrefix.base64_encode(gzdeflate(serialize($this->links))).self::$phpSuffix | ||
375 | ); | ||
376 | |||
377 | } | 350 | } |
378 | 351 | ||
379 | /** | 352 | /** |
diff --git a/application/exceptions/IOException.php b/application/exceptions/IOException.php new file mode 100644 index 00000000..b563b23d --- /dev/null +++ b/application/exceptions/IOException.php | |||
@@ -0,0 +1,22 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Exception class thrown when a filesystem access failure happens | ||
5 | */ | ||
6 | class IOException extends Exception | ||
7 | { | ||
8 | private $path; | ||
9 | |||
10 | /** | ||
11 | * Construct a new IOException | ||
12 | * | ||
13 | * @param string $path path to the resource that cannot be accessed | ||
14 | * @param string $message Custom exception message. | ||
15 | */ | ||
16 | public function __construct($path, $message = '') | ||
17 | { | ||
18 | $this->path = $path; | ||
19 | $this->message = empty($message) ? 'Error accessing' : $message; | ||
20 | $this->message .= ' "' . $this->path .'"'; | ||
21 | } | ||
22 | } | ||