Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
54.24% |
32 / 59 |
|
31.25% |
5 / 16 |
CRAP | |
0.00% |
0 / 1 |
local | |
54.24% |
32 / 59 |
|
31.25% |
5 / 16 |
123.10 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
configure | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
put_contents | |
50.00% |
2 / 4 |
|
0.00% |
0 / 1 |
2.50 | |||
get_contents | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
exists | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
delete | |
33.33% |
1 / 3 |
|
0.00% |
0 / 1 |
3.19 | |||
rename | |
50.00% |
2 / 4 |
|
0.00% |
0 / 1 |
2.50 | |||
copy | |
50.00% |
2 / 4 |
|
0.00% |
0 / 1 |
2.50 | |||
create_dir | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
ensure_directory_exists | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
get_path | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
get_filename | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
read_stream | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
write_stream | |
62.50% |
5 / 8 |
|
0.00% |
0 / 1 |
3.47 | |||
file_size | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
free_space | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\storage\adapter; |
15 | |
16 | use phpbb\storage\stream_interface; |
17 | use phpbb\storage\exception\storage_exception; |
18 | use phpbb\filesystem\exception\filesystem_exception; |
19 | use phpbb\filesystem\filesystem; |
20 | use phpbb\filesystem\helper as filesystem_helper; |
21 | |
22 | /** |
23 | * Experimental |
24 | */ |
25 | class local implements adapter_interface, stream_interface |
26 | { |
27 | /** |
28 | * Filesystem component |
29 | * |
30 | * @var filesystem |
31 | */ |
32 | protected $filesystem; |
33 | |
34 | /** |
35 | * @var string path |
36 | */ |
37 | protected $phpbb_root_path; |
38 | |
39 | /** |
40 | * Absolute path to the storage folder |
41 | * Always finish with DIRECTORY_SEPARATOR |
42 | * Example: |
43 | * - /var/www/phpBB/images/avatar/upload/ |
44 | * - C:\phpBB\images\avatars\upload\ |
45 | * |
46 | * @var string path |
47 | */ |
48 | protected $root_path; |
49 | |
50 | /** |
51 | * Relative path from $phpbb_root_path to the storage folder |
52 | * Always finish with slash (/) character |
53 | * Example: |
54 | * - images/avatars/upload/ |
55 | * |
56 | * @var string path |
57 | */ |
58 | protected $path; |
59 | |
60 | /** |
61 | * Constructor |
62 | * |
63 | * @param filesystem $filesystem |
64 | * @param string $phpbb_root_path |
65 | */ |
66 | public function __construct(filesystem $filesystem, string $phpbb_root_path) |
67 | { |
68 | $this->filesystem = $filesystem; |
69 | $this->phpbb_root_path = $phpbb_root_path; |
70 | } |
71 | |
72 | /** |
73 | * {@inheritdoc} |
74 | */ |
75 | public function configure(array $options): void |
76 | { |
77 | $this->path = $options['path']; |
78 | |
79 | if (substr($this->path, -1, 1) !== '/') |
80 | { |
81 | $this->path = $this->path . '/'; |
82 | } |
83 | |
84 | $this->root_path = filesystem_helper::realpath($this->phpbb_root_path . $options['path']) . DIRECTORY_SEPARATOR; |
85 | } |
86 | |
87 | /** |
88 | * {@inheritdoc} |
89 | */ |
90 | public function put_contents(string $path, string $content): void |
91 | { |
92 | $this->ensure_directory_exists($path); |
93 | |
94 | try |
95 | { |
96 | $this->filesystem->dump_file($this->root_path . $this->get_path($path) . $this->get_filename($path), $content); |
97 | } |
98 | catch (filesystem_exception $e) |
99 | { |
100 | throw new storage_exception('STORAGE_CANNOT_WRITE_FILE', $path, array(), $e); |
101 | } |
102 | } |
103 | |
104 | /** |
105 | * {@inheritdoc} |
106 | */ |
107 | public function get_contents(string $path): string |
108 | { |
109 | $content = @file_get_contents($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
110 | |
111 | if ($content === false) |
112 | { |
113 | throw new storage_exception('STORAGE_CANNOT_READ_FILE', $path); |
114 | } |
115 | |
116 | return $content; |
117 | } |
118 | |
119 | /** |
120 | * {@inheritdoc} |
121 | */ |
122 | public function exists(string $path): bool |
123 | { |
124 | return $this->filesystem->exists($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
125 | } |
126 | |
127 | /** |
128 | * {@inheritdoc} |
129 | */ |
130 | public function delete(string $path): void |
131 | { |
132 | try |
133 | { |
134 | $this->filesystem->remove($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
135 | } |
136 | catch (filesystem_exception $e) |
137 | { |
138 | throw new storage_exception('STORAGE_CANNOT_DELETE', $path, array(), $e); |
139 | } |
140 | } |
141 | |
142 | /** |
143 | * {@inheritdoc} |
144 | */ |
145 | public function rename(string $path_orig, string $path_dest): void |
146 | { |
147 | $this->ensure_directory_exists($path_dest); |
148 | |
149 | try |
150 | { |
151 | $this->filesystem->rename($this->root_path . $this->get_path($path_orig) . $this->get_filename($path_orig), $this->root_path . $this->get_path($path_dest) . $this->get_filename($path_dest), false); |
152 | } |
153 | catch (filesystem_exception $e) |
154 | { |
155 | throw new storage_exception('STORAGE_CANNOT_RENAME', $path_orig, array(), $e); |
156 | } |
157 | } |
158 | |
159 | /** |
160 | * {@inheritdoc} |
161 | */ |
162 | public function copy(string $path_orig, string $path_dest): void |
163 | { |
164 | $this->ensure_directory_exists($path_dest); |
165 | |
166 | try |
167 | { |
168 | $this->filesystem->copy($this->root_path . $this->get_path($path_orig) . $this->get_filename($path_orig), $this->root_path . $this->get_path($path_dest) . $this->get_filename($path_dest), false); |
169 | } |
170 | catch (filesystem_exception $e) |
171 | { |
172 | throw new storage_exception('STORAGE_CANNOT_COPY', $path_orig, array(), $e); |
173 | } |
174 | } |
175 | |
176 | /** |
177 | * Creates a directory recursively. |
178 | * |
179 | * @param string $path The directory path |
180 | * |
181 | * @throws storage_exception On any directory creation failure |
182 | */ |
183 | protected function create_dir(string $path): void |
184 | { |
185 | try |
186 | { |
187 | $this->filesystem->mkdir($this->root_path . $path); |
188 | } |
189 | catch (filesystem_exception $e) |
190 | { |
191 | throw new storage_exception('STORAGE_CANNOT_CREATE_DIR', $path, array(), $e); |
192 | } |
193 | } |
194 | |
195 | /** |
196 | * Ensures that the directory of a file exists. |
197 | * |
198 | * @param string $path The file path |
199 | * |
200 | * @throws storage_exception On any directory creation failure |
201 | */ |
202 | protected function ensure_directory_exists(string $path): void |
203 | { |
204 | $path = dirname($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
205 | $path = filesystem_helper::make_path_relative($path, $this->root_path); |
206 | |
207 | if (!$this->exists($path)) |
208 | { |
209 | $this->create_dir($path); |
210 | } |
211 | } |
212 | |
213 | /** |
214 | * Get the path to the file |
215 | * |
216 | * @param string $path The file path |
217 | * @return string |
218 | */ |
219 | protected function get_path(string $path): string |
220 | { |
221 | $dirname = dirname($path); |
222 | $dirname = ($dirname != '.') ? $dirname . DIRECTORY_SEPARATOR : ''; |
223 | |
224 | return $dirname; |
225 | } |
226 | |
227 | /** |
228 | * To be used in other PR |
229 | * |
230 | * @param string $path The file path |
231 | * @return string |
232 | */ |
233 | protected function get_filename(string $path): string |
234 | { |
235 | return basename($path); |
236 | } |
237 | |
238 | /** |
239 | * {@inheritdoc} |
240 | */ |
241 | public function read_stream(string $path) |
242 | { |
243 | $stream = @fopen($this->root_path . $this->get_path($path) . $this->get_filename($path), 'rb'); |
244 | |
245 | if (!$stream) |
246 | { |
247 | throw new storage_exception('STORAGE_CANNOT_OPEN_FILE', $path); |
248 | } |
249 | |
250 | return $stream; |
251 | } |
252 | |
253 | /** |
254 | * {@inheritdoc} |
255 | */ |
256 | public function write_stream(string $path, $resource): void |
257 | { |
258 | $this->ensure_directory_exists($path); |
259 | |
260 | $stream = @fopen($this->root_path . $this->get_path($path) . $this->get_filename($path), 'w+b'); |
261 | |
262 | if (!$stream) |
263 | { |
264 | throw new storage_exception('STORAGE_CANNOT_CREATE_FILE', $path); |
265 | } |
266 | |
267 | if (stream_copy_to_stream($resource, $stream) === false) |
268 | { |
269 | fclose($stream); |
270 | throw new storage_exception('STORAGE_CANNOT_COPY_RESOURCE'); |
271 | } |
272 | |
273 | fclose($stream); |
274 | } |
275 | |
276 | /** |
277 | * {@inheritdoc} |
278 | */ |
279 | public function file_size(string $path): int |
280 | { |
281 | $size = @filesize($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
282 | |
283 | if ($size === null) |
284 | { |
285 | throw new storage_exception('STORAGE_CANNOT_GET_FILESIZE'); |
286 | } |
287 | |
288 | return $size; |
289 | } |
290 | |
291 | /** |
292 | * {@inheritdoc} |
293 | */ |
294 | public function free_space(): float |
295 | { |
296 | if (function_exists('disk_free_space')) |
297 | { |
298 | $free_space = @disk_free_space($this->root_path); |
299 | |
300 | if ($free_space === false) |
301 | { |
302 | throw new storage_exception('STORAGE_CANNOT_GET_FREE_SPACE'); |
303 | } |
304 | } |
305 | else |
306 | { |
307 | throw new storage_exception('STORAGE_CANNOT_GET_FREE_SPACE'); |
308 | } |
309 | |
310 | return $free_space; |
311 | } |
312 | } |