This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace NokitaKaze\KeyValue; |
||
4 | |||
5 | use NokitaKaze\Mutex\FileMutex; |
||
6 | |||
7 | /** |
||
8 | * Class Key-value хранилище, использующее обыкновенные файлы |
||
9 | */ |
||
10 | class FileStorage extends AbstractStorage { |
||
11 | var $folder; |
||
12 | protected $_multi_folder = false; |
||
13 | const ERROR_CODE = 100; |
||
14 | |||
15 | /** |
||
16 | * @param KeyValueSettings|object $settings |
||
17 | * |
||
18 | * @throws KeyValueException |
||
19 | */ |
||
20 | 155 | function __construct($settings) { |
|
21 | 155 | if (!isset($settings->storage_type)) { |
|
22 | 150 | $settings->storage_type = self::StorageTemporary; |
|
23 | 30 | } |
|
24 | 155 | switch ($settings->storage_type) { |
|
25 | 155 | case self::StorageTemporary: |
|
26 | 155 | $this->folder = sys_get_temp_dir(); |
|
27 | 155 | break; |
|
28 | 5 | case self::StoragePersistent: |
|
29 | 5 | $this->folder = FileMutex::getDirectoryString(); |
|
30 | 5 | break; |
|
31 | 1 | default: |
|
32 | 5 | throw new KeyValueException('Constructor settings is malformed. Storage type can not be equal '. |
|
33 | 5 | $settings->storage_type, self::ERROR_CODE + 1); |
|
34 | 31 | } |
|
35 | 155 | if (isset($settings->folder)) { |
|
36 | 150 | $this->folder = $settings->folder; |
|
37 | 30 | } |
|
38 | 155 | if (isset($settings->multi_folder)) { |
|
39 | 35 | $this->_multi_folder = (boolean) $settings->multi_folder; |
|
40 | 7 | } |
|
41 | |||
42 | 155 | $this->settings = $settings; |
|
43 | 155 | $this->standard_prefix_strategy(); |
|
44 | 155 | } |
|
45 | |||
46 | /** |
||
47 | * @param string $key Название ключа |
||
48 | * @param mixed $value Новое значение |
||
49 | * @param double|integer $ttl Кол-во секунд, после которых значение будет считаться просроченным |
||
50 | * |
||
51 | * @throws KeyValueException |
||
52 | */ |
||
53 | 60 | function set_value($key, $value, $ttl = 315576000) { |
|
54 | 60 | $ts1 = microtime(true); |
|
55 | 60 | $data = $this->form_datum_value($key, $value, $ttl); |
|
56 | 60 | self::create_path($this->folder, $this->_multi_folder, $key); |
|
57 | 55 | $this->get_lock($key); |
|
58 | 55 | $temporary_filename = $this->get_filename($key).'.tmp'; |
|
59 | 55 | $result = @file_put_contents($temporary_filename, serialize($data), LOCK_EX); |
|
60 | 55 | if ($result === false) { |
|
61 | 5 | $this->release_lock(); |
|
62 | 5 | throw new KeyValueException('Can not save value', self::ERROR_CODE + 3); |
|
63 | } |
||
64 | 55 | chmod($temporary_filename, 6 << 6); |
|
65 | 55 | if (!rename($temporary_filename, $this->get_filename($key))) { |
|
66 | // @codeCoverageIgnoreStart |
||
67 | @unlink($temporary_filename); |
||
0 ignored issues
–
show
|
|||
68 | $this->release_lock(); |
||
69 | throw new KeyValueException('Can not rename db file', self::ERROR_CODE + 4); |
||
70 | // @codeCoverageIgnoreEnd |
||
71 | } |
||
72 | 55 | $this->release_lock(); |
|
73 | 55 | self::add_profiling(microtime(true) - $ts1, static::class, 'set_value'); |
|
74 | 55 | } |
|
75 | |||
76 | /** |
||
77 | * Создаём папку |
||
78 | * |
||
79 | * @param string $folder |
||
80 | * @param boolean $multi_folder |
||
81 | * @param string $key |
||
82 | * |
||
83 | * @throws KeyValueException |
||
84 | */ |
||
85 | 65 | protected static function create_path($folder, $multi_folder, $key) { |
|
86 | 65 | if (!file_exists($folder)) { |
|
87 | 10 | if (!file_exists(dirname($folder))) { |
|
88 | 10 | throw new KeyValueException(sprintf('Folder %s does not exist', dirname($folder)), |
|
89 | 10 | self::ERROR_CODE + 5); |
|
90 | } else { |
||
91 | 5 | @mkdir($folder); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
92 | 5 | @chmod($folder, (7 << 6) | (7 << 3)); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
93 | } |
||
94 | 1 | } |
|
95 | |||
96 | 60 | if (!$multi_folder) { |
|
97 | 40 | return; |
|
98 | } |
||
99 | 30 | $hash = hash('sha512', $key); |
|
100 | 30 | $folder .= '/'.substr($hash, 0, 2); |
|
101 | 30 | if (!file_exists($folder)) { |
|
102 | 30 | @mkdir($folder); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
103 | 30 | @chmod($folder, (7 << 6) | (7 << 3)); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
104 | 6 | } |
|
105 | 30 | $folder .= '/'.substr($hash, 2, 2); |
|
106 | 30 | if (!file_exists($folder)) { |
|
107 | 30 | @mkdir($folder); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
108 | 30 | @chmod($folder, (7 << 6) | (7 << 3)); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
109 | 6 | } |
|
110 | 30 | } |
|
111 | |||
112 | /** |
||
113 | * @param string $key |
||
114 | * |
||
115 | * @return object|null |
||
116 | */ |
||
117 | 65 | protected function get_value_full_clear($key) { |
|
118 | 65 | $filename = $this->get_filename($key); |
|
119 | 65 | if (!file_exists($filename)) { |
|
120 | 65 | return null; |
|
121 | } |
||
122 | 60 | $this->get_lock($key); |
|
123 | 60 | $buf = @file_get_contents($filename); |
|
124 | 60 | $this->release_lock(); |
|
125 | 60 | if ($buf === false) { |
|
126 | 5 | return null; |
|
127 | } |
||
128 | 60 | $data = @unserialize($buf); |
|
129 | 60 | if (($data === false) and ($buf != serialize(false))) { |
|
130 | 5 | return null; |
|
131 | } |
||
132 | |||
133 | 60 | return $data; |
|
134 | } |
||
135 | |||
136 | /** |
||
137 | * @param string $key |
||
138 | * |
||
139 | * @return string |
||
140 | */ |
||
141 | 145 | function get_filename($key) { |
|
142 | 145 | return $this->get_folder($key).'/ascetkey_'.$this->_prefix.hash('sha512', $key).'.dat'; |
|
143 | } |
||
144 | |||
145 | /** |
||
146 | * @param string $key |
||
147 | * |
||
148 | * @return string |
||
149 | */ |
||
150 | 65 | function get_folder($key) { |
|
151 | 65 | $full_folder = $this->folder; |
|
152 | 65 | if ($this->_multi_folder) { |
|
153 | 25 | $hash = hash('sha512', $key); |
|
154 | 25 | $full_folder .= sprintf('/%s/%s', substr($hash, 0, 2), substr($hash, 2, 2)); |
|
155 | 5 | } |
|
156 | |||
157 | 65 | return $full_folder; |
|
158 | } |
||
159 | |||
160 | /** |
||
161 | * Key for NokitaKaze\Mutex\MutexInterface |
||
162 | * |
||
163 | * @param string $key |
||
164 | * |
||
165 | * @return string |
||
166 | */ |
||
167 | 145 | function get_mutex_key_name($key) { |
|
168 | // @hint Мы используем sha256, а не sha512, потому что иначе у нас просто не хватит длины |
||
169 | 145 | return 'ascetkey_'.hash('sha256', $this->get_filename($key)); |
|
170 | } |
||
171 | |||
172 | /** |
||
173 | * Создаём мьютекс, соответствующий ключу и кладём его в _locks |
||
174 | * |
||
175 | * @param string $key |
||
176 | */ |
||
177 | 65 | protected function create_lock($key) { |
|
178 | // @todo Любой мьютекс |
||
179 | 65 | $this->_locks[$key] = new FileMutex([ |
|
180 | 65 | 'name' => $this->get_mutex_key_name($key), |
|
181 | 65 | 'prefix' => '', |
|
182 | 65 | 'folder' => $this->get_folder($key), |
|
183 | 13 | ]); |
|
184 | 65 | } |
|
185 | |||
186 | /** |
||
187 | * @param string $key |
||
188 | */ |
||
189 | 30 | function delete_value($key) { |
|
190 | 30 | $ts1 = microtime(true); |
|
191 | 30 | $filename = $this->get_filename($key); |
|
192 | 30 | if (!file_exists($filename)) { |
|
193 | 30 | self::add_profiling(microtime(true) - $ts1, static::class, 'delete_value'); |
|
194 | |||
195 | 30 | return; |
|
196 | } |
||
197 | 20 | $this->get_lock($key); |
|
198 | 20 | @unlink($filename); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
199 | 20 | $this->release_lock(); |
|
200 | 20 | self::add_profiling(microtime(true) - $ts1, static::class, 'delete_value'); |
|
201 | 20 | } |
|
202 | |||
203 | /** |
||
204 | * Санация части regexp для добавления напрямую в regexp |
||
205 | * |
||
206 | * @param string $text Часть, которую над санировать |
||
207 | * |
||
208 | * @return string |
||
209 | * @codeCoverageIgnore |
||
210 | */ |
||
211 | protected static function sad_safe_reg($text) { |
||
212 | $ar = '.-\\/[]{}()*?+^$|'; |
||
213 | $s = ''; |
||
214 | for ($i = 0; $i < strlen($text); $i++) { |
||
215 | if (strpos($ar, $text[$i]) !== false) { |
||
216 | $s .= '\\'.$text[$i]; |
||
217 | } else { |
||
218 | $s .= $text[$i]; |
||
219 | } |
||
220 | } |
||
221 | |||
222 | return $s; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * @param string $folder |
||
227 | */ |
||
228 | 20 | protected function delete_all_files_in_folder($folder) { |
|
229 | 20 | foreach (scandir($folder) as $d) { |
|
230 | 20 | if (!in_array($d, ['.', '..']) and |
|
231 | 20 | preg_match('|^ascetkey_'.self::sad_safe_reg($this->_prefix).'[a-f0-9]{128,128}\\.dat$|', $d) |
|
232 | 4 | ) { |
|
233 | 20 | unlink($folder.'/'.$d); |
|
234 | 4 | } |
|
235 | 4 | } |
|
236 | 20 | } |
|
237 | |||
238 | 25 | function clear() { |
|
239 | 25 | if (!file_exists($this->folder) or !is_dir($this->folder)) { |
|
240 | 5 | return; |
|
241 | } |
||
242 | 20 | if (!$this->_multi_folder) { |
|
243 | 10 | $this->delete_all_files_in_folder($this->folder); |
|
244 | 2 | } else { |
|
245 | 10 | for ($i = 0; $i < 256; $i++) { |
|
246 | // @todo заменить на pack |
||
247 | 10 | if ($i < 16) { |
|
248 | 10 | $k1 = '0'.dechex($i); |
|
249 | 2 | } else { |
|
250 | 10 | $k1 = dechex($i); |
|
251 | } |
||
252 | 10 | if (!file_exists($this->folder.'/'.$k1) or !is_dir($this->folder.'/'.$k1)) { |
|
253 | 5 | continue; |
|
254 | } |
||
255 | |||
256 | 10 | for ($j = 0; $j < 256; $j++) { |
|
257 | // @todo заменить на pack |
||
258 | 10 | if ($j < 16) { |
|
259 | 10 | $k2 = '0'.dechex($j); |
|
260 | 2 | } else { |
|
261 | 10 | $k2 = dechex($j); |
|
262 | } |
||
263 | |||
264 | 10 | $full_folder = $this->folder.'/'.$k1.'/'.$k2; |
|
265 | 10 | if (file_exists($full_folder) and is_dir($full_folder)) { |
|
266 | 10 | $this->delete_all_files_in_folder($full_folder); |
|
267 | 2 | } |
|
268 | 2 | } |
|
269 | 2 | } |
|
270 | } |
||
271 | 20 | } |
|
272 | } |
||
273 | |||
274 | ?> |
If you suppress an error, we recommend checking for the error condition explicitly: