Completed
Push — master ( 6e4edc...cbed4d )
by Felix
02:48
created

FileStorage::get()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 10
ccs 7
cts 7
cp 1
rs 9.4285
cc 3
eloc 6
nc 2
nop 1
crap 3
1
<?php
2
/**
3
 * PhPsst.
4
 *
5
 * @copyright Copyright (c) 2016 Felix Sandström
6
 * @license   MIT
7
 */
8
9
namespace PhPsst\Storage;
10
11
use PhPsst\Password;
12
use PhPsst\PhPsstException;
13
14
/**
15
 */
16
class FileStorage extends Storage
17
{
18
    /**
19
     * @var string
20
     */
21
    protected $dir;
22
23
    /**
24
     * @var int
25
     */
26
    protected $gcProbability;
27
28
    /**
29
     * @const string
30
     */
31
    const FILE_SUFFIX = '.phpsst';
32
33
    /**
34
     * FileStorage constructor.
35
     * @param string $dir
36
     * @param int $gcProbability
37
     */
38 10
    public function __construct($dir, $gcProbability)
39
    {
40 10
        $dir = rtrim($dir, '/') . '/';
41 10
        if (empty($dir) || !is_dir($dir)) {
42 1
            throw new \RuntimeException('Invalid directory path');
43
        }
44
45 9
        if ($gcProbability < 0) {
46 1
            throw new \LogicException('Invalid value for gcProbability');
47
        }
48
49 8
        $this->dir = $dir;
50 8
        $this->gcProbability = $gcProbability;
51 8
    }
52
53
    /**
54
     * @param Password $password
55
     * @param bool $allowOverwrite
56
     */
57 8
    public function store(Password $password, $allowOverwrite = false)
58
    {
59 8
        if (!$allowOverwrite && file_exists($this->getFileName($password))) {
60 2
            throw new PhPsstException('The ID already exists', PhPsstException::ID_IS_ALREADY_TAKEN);
61
        }
62
63 8
        $this->writeFile($password);
64 7
    }
65
66
    /**
67
     * @param $key
68
     * @return Password|null
69
     */
70 3
    public function get($key)
71
    {
72 3
        $password = null;
73 3
        if (file_exists($this->getFileNameFromKey($key))
74 3
            && ($passwordData = file_get_contents($this->getFileNameFromKey($key)))) {
75 3
            $password = $this->getPasswordFromJson($passwordData);
76 3
        }
77
78 3
        return $password;
79
    }
80
81
    /**
82
     * @param Password $password
83
     */
84 2
    public function delete(Password $password)
85
    {
86 2
        unlink($this->getFileName($password));
87 2
    }
88
89
    /**
90
     */
91 6
    protected function garbageCollection()
92
    {
93 6
        if (!$this->gcProbability || rand(1, $this->gcProbability) !== 1) {
94 1
            return;
95
        }
96
97 5
        $files = array_diff(scandir($this->dir), array('.', '..'));
98 5
        foreach ($files as $file) {
99 5
            if (($jsonData = json_decode(file_get_contents($this->dir . $file)))) {
100 5
                if ($jsonData->ttlTime < time()) {
101 1
                    unlink($this->dir . $file);
102 1
                }
103 5
            }
104 5
        }
105 5
    }
106
107
    /**
108
     * @param Password $password
109
     */
110 7
    protected function writeFile(Password $password)
111
    {
112 7
        $jsonData = $this->getJsonFromPassword($password);
113
114 7
        $fileName = $this->getFileName($password);
115 7
        if (!is_writable(dirname($fileName)) || !file_put_contents($fileName, $jsonData)) {
116 1
            throw new \RuntimeException('Can not write file');
117
        }
118
119 6
        $this->garbageCollection();
120 6
    }
121
122
    /**
123
     * @param Password $password
124
     * @return string
125
     */
126 4
    protected function getFileName(Password $password)
127
    {
128 4
        return $this->getFileNameFromKey($password->getId());
129
    }
130
131
    /**
132
     * @param string $key
133
     * @return string
134
     */
135 4
    protected function getFileNameFromKey($key)
136
    {
137 4
        return $this->dir . $key . self::FILE_SUFFIX;
138
    }
139
}
140