Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
48.57% |
34 / 70 |
|
23.81% |
5 / 21 |
CRAP | |
0.00% |
0 / 1 |
local | |
48.57% |
34 / 70 |
|
23.81% |
5 / 21 |
223.22 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
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 | |||
file_mimetype | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
image_dimensions | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
file_image_width | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
file_image_height | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
get_link | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
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 | use phpbb\mimetype\guesser; |
22 | use FastImageSize\FastImageSize; |
23 | |
24 | /** |
25 | * Experimental |
26 | */ |
27 | class local implements adapter_interface, stream_interface |
28 | { |
29 | /** |
30 | * Filesystem component |
31 | * |
32 | * @var filesystem |
33 | */ |
34 | protected $filesystem; |
35 | |
36 | /** |
37 | * FastImageSize |
38 | * |
39 | * @var FastImageSize |
40 | */ |
41 | protected $imagesize; |
42 | |
43 | /** |
44 | * Mimetype Guesser component |
45 | * |
46 | * @var guesser |
47 | */ |
48 | protected $mimetype_guesser; |
49 | |
50 | /** |
51 | * @var string path |
52 | */ |
53 | protected $phpbb_root_path; |
54 | |
55 | /** |
56 | * Absolute path to the storage folder |
57 | * Always finish with DIRECTORY_SEPARATOR |
58 | * Example: |
59 | * - /var/www/phpBB/images/avatar/upload/ |
60 | * - C:\phpBB\images\avatars\upload\ |
61 | * |
62 | * @var string path |
63 | */ |
64 | protected $root_path; |
65 | |
66 | /** |
67 | * Relative path from $phpbb_root_path to the storage folder |
68 | * Always finish with slash (/) character |
69 | * Example: |
70 | * - images/avatars/upload/ |
71 | * |
72 | * @var string path |
73 | */ |
74 | protected $path; |
75 | |
76 | /** |
77 | * Constructor |
78 | * |
79 | * @param filesystem $filesystem |
80 | * @param FastImageSize $imagesize |
81 | * @param guesser $mimetype_guesser |
82 | * @param string $phpbb_root_path |
83 | */ |
84 | public function __construct(filesystem $filesystem, FastImageSize $imagesize, guesser $mimetype_guesser, string $phpbb_root_path) |
85 | { |
86 | $this->filesystem = $filesystem; |
87 | $this->imagesize = $imagesize; |
88 | $this->mimetype_guesser = $mimetype_guesser; |
89 | $this->phpbb_root_path = $phpbb_root_path; |
90 | } |
91 | |
92 | /** |
93 | * {@inheritdoc} |
94 | */ |
95 | public function configure(array $options): void |
96 | { |
97 | $this->path = $options['path']; |
98 | |
99 | if (substr($this->path, -1, 1) !== '/') |
100 | { |
101 | $this->path = $this->path . '/'; |
102 | } |
103 | |
104 | $this->root_path = filesystem_helper::realpath($this->phpbb_root_path . $options['path']) . DIRECTORY_SEPARATOR; |
105 | } |
106 | |
107 | /** |
108 | * {@inheritdoc} |
109 | */ |
110 | public function put_contents(string $path, string $content): void |
111 | { |
112 | $this->ensure_directory_exists($path); |
113 | |
114 | try |
115 | { |
116 | $this->filesystem->dump_file($this->root_path . $this->get_path($path) . $this->get_filename($path), $content); |
117 | } |
118 | catch (filesystem_exception $e) |
119 | { |
120 | throw new storage_exception('STORAGE_CANNOT_WRITE_FILE', $path, array(), $e); |
121 | } |
122 | } |
123 | |
124 | /** |
125 | * {@inheritdoc} |
126 | */ |
127 | public function get_contents(string $path): string |
128 | { |
129 | $content = @file_get_contents($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
130 | |
131 | if ($content === false) |
132 | { |
133 | throw new storage_exception('STORAGE_CANNOT_READ_FILE', $path); |
134 | } |
135 | |
136 | return $content; |
137 | } |
138 | |
139 | /** |
140 | * {@inheritdoc} |
141 | */ |
142 | public function exists(string $path): bool |
143 | { |
144 | return $this->filesystem->exists($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
145 | } |
146 | |
147 | /** |
148 | * {@inheritdoc} |
149 | */ |
150 | public function delete(string $path): void |
151 | { |
152 | try |
153 | { |
154 | $this->filesystem->remove($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
155 | } |
156 | catch (filesystem_exception $e) |
157 | { |
158 | throw new storage_exception('STORAGE_CANNOT_DELETE', $path, array(), $e); |
159 | } |
160 | } |
161 | |
162 | /** |
163 | * {@inheritdoc} |
164 | */ |
165 | public function rename(string $path_orig, string $path_dest): void |
166 | { |
167 | $this->ensure_directory_exists($path_dest); |
168 | |
169 | try |
170 | { |
171 | $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); |
172 | } |
173 | catch (filesystem_exception $e) |
174 | { |
175 | throw new storage_exception('STORAGE_CANNOT_RENAME', $path_orig, array(), $e); |
176 | } |
177 | } |
178 | |
179 | /** |
180 | * {@inheritdoc} |
181 | */ |
182 | public function copy(string $path_orig, string $path_dest): void |
183 | { |
184 | $this->ensure_directory_exists($path_dest); |
185 | |
186 | try |
187 | { |
188 | $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); |
189 | } |
190 | catch (filesystem_exception $e) |
191 | { |
192 | throw new storage_exception('STORAGE_CANNOT_COPY', $path_orig, array(), $e); |
193 | } |
194 | } |
195 | |
196 | /** |
197 | * Creates a directory recursively. |
198 | * |
199 | * @param string $path The directory path |
200 | * |
201 | * @throws storage_exception On any directory creation failure |
202 | */ |
203 | protected function create_dir(string $path): void |
204 | { |
205 | try |
206 | { |
207 | $this->filesystem->mkdir($this->root_path . $path); |
208 | } |
209 | catch (filesystem_exception $e) |
210 | { |
211 | throw new storage_exception('STORAGE_CANNOT_CREATE_DIR', $path, array(), $e); |
212 | } |
213 | } |
214 | |
215 | /** |
216 | * Ensures that the directory of a file exists. |
217 | * |
218 | * @param string $path The file path |
219 | * |
220 | * @throws storage_exception On any directory creation failure |
221 | */ |
222 | protected function ensure_directory_exists(string $path): void |
223 | { |
224 | $path = dirname($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
225 | $path = filesystem_helper::make_path_relative($path, $this->root_path); |
226 | |
227 | if (!$this->exists($path)) |
228 | { |
229 | $this->create_dir($path); |
230 | } |
231 | } |
232 | |
233 | /** |
234 | * Get the path to the file |
235 | * |
236 | * @param string $path The file path |
237 | * @return string |
238 | */ |
239 | protected function get_path(string $path): string |
240 | { |
241 | $dirname = dirname($path); |
242 | $dirname = ($dirname != '.') ? $dirname . DIRECTORY_SEPARATOR : ''; |
243 | |
244 | return $dirname; |
245 | } |
246 | |
247 | /** |
248 | * To be used in other PR |
249 | * |
250 | * @param string $path The file path |
251 | * @return string |
252 | */ |
253 | protected function get_filename(string $path): string |
254 | { |
255 | return basename($path); |
256 | } |
257 | |
258 | /** |
259 | * {@inheritdoc} |
260 | */ |
261 | public function read_stream(string $path) |
262 | { |
263 | $stream = @fopen($this->root_path . $this->get_path($path) . $this->get_filename($path), 'rb'); |
264 | |
265 | if (!$stream) |
266 | { |
267 | throw new storage_exception('STORAGE_CANNOT_OPEN_FILE', $path); |
268 | } |
269 | |
270 | return $stream; |
271 | } |
272 | |
273 | /** |
274 | * {@inheritdoc} |
275 | */ |
276 | public function write_stream(string $path, $resource): void |
277 | { |
278 | $this->ensure_directory_exists($path); |
279 | |
280 | $stream = @fopen($this->root_path . $this->get_path($path) . $this->get_filename($path), 'w+b'); |
281 | |
282 | if (!$stream) |
283 | { |
284 | throw new storage_exception('STORAGE_CANNOT_CREATE_FILE', $path); |
285 | } |
286 | |
287 | if (stream_copy_to_stream($resource, $stream) === false) |
288 | { |
289 | fclose($stream); |
290 | throw new storage_exception('STORAGE_CANNOT_COPY_RESOURCE'); |
291 | } |
292 | |
293 | fclose($stream); |
294 | } |
295 | |
296 | /** |
297 | * Get file size |
298 | * |
299 | * @param string $path The file |
300 | * |
301 | * @return array Properties |
302 | * |
303 | * @throws storage_exception When cannot get size |
304 | */ |
305 | public function file_size(string $path): array |
306 | { |
307 | $size = @filesize($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
308 | |
309 | if ($size === null) |
310 | { |
311 | throw new storage_exception('STORAGE_CANNOT_GET_FILESIZE'); |
312 | } |
313 | |
314 | return ['size' => $size]; |
315 | } |
316 | |
317 | /** |
318 | * Get file mimetype |
319 | * |
320 | * @param string $path The file |
321 | * |
322 | * @return array Properties |
323 | */ |
324 | public function file_mimetype(string $path): array |
325 | { |
326 | return ['mimetype' => $this->mimetype_guesser->guess($this->root_path . $this->get_path($path) . $this->get_filename($path))]; |
327 | } |
328 | |
329 | /** |
330 | * Get image dimensions |
331 | * |
332 | * @param string $path The file |
333 | * |
334 | * @return array Properties |
335 | */ |
336 | protected function image_dimensions(string $path): array |
337 | { |
338 | $size = $this->imagesize->getImageSize($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
339 | |
340 | // For not supported types like swf |
341 | if ($size === false) |
342 | { |
343 | $imsize = getimagesize($this->root_path . $this->get_path($path) . $this->get_filename($path)); |
344 | $size = ['width' => $imsize[0], 'height' => $imsize[1]]; |
345 | } |
346 | |
347 | return ['image_width' => $size['width'], 'image_height' => $size['height']]; |
348 | } |
349 | |
350 | /** |
351 | * Get image width |
352 | * |
353 | * @param string $path The file |
354 | * |
355 | * @return array Properties |
356 | */ |
357 | public function file_image_width(string $path): array |
358 | { |
359 | return $this->image_dimensions($path); |
360 | } |
361 | |
362 | /** |
363 | * Get image height |
364 | * |
365 | * @param string $path The file |
366 | * |
367 | * @return array Properties |
368 | */ |
369 | public function file_image_height(string $path): array |
370 | { |
371 | return $this->image_dimensions($path); |
372 | } |
373 | |
374 | /** |
375 | * {@inheritdoc} |
376 | */ |
377 | public function get_link(string $path): string |
378 | { |
379 | return generate_board_url() . '/' . $this->path . $path; |
380 | } |
381 | |
382 | /** |
383 | * {@inheritdoc} |
384 | */ |
385 | public function free_space(): float |
386 | { |
387 | if (function_exists('disk_free_space')) |
388 | { |
389 | $free_space = @disk_free_space($this->root_path); |
390 | |
391 | if ($free_space === false) |
392 | { |
393 | throw new storage_exception('STORAGE_CANNOT_GET_FREE_SPACE'); |
394 | } |
395 | } |
396 | else |
397 | { |
398 | throw new storage_exception('STORAGE_CANNOT_GET_FREE_SPACE'); |
399 | } |
400 | |
401 | return $free_space; |
402 | } |
403 | } |