Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 239 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
acp_storage | |
0.00% |
0 / 237 |
|
0.00% |
0 / 11 |
5402 | |
0.00% |
0 / 1 |
main | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
6 | |||
settings | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
56 | |||
update_action | |
0.00% |
0 / 49 |
|
0.00% |
0 / 1 |
182 | |||
update_inprogress | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
settings_form | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
72 | |||
get_modified_storages | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
42 | |||
storage_stats | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
12 | |||
display_progress_page | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
get_storage_update_progress | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
20 | |||
validate_data | |
0.00% |
0 / 46 |
|
0.00% |
0 / 1 |
462 | |||
validate_path | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
56 |
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 | use phpbb\db\driver\driver_interface; |
15 | use phpbb\di\service_collection; |
16 | use phpbb\language\language; |
17 | use phpbb\log\log_interface; |
18 | use phpbb\request\request; |
19 | use phpbb\storage\exception\storage_exception; |
20 | use phpbb\storage\helper; |
21 | use phpbb\storage\state_helper; |
22 | use phpbb\storage\update_type; |
23 | use phpbb\template\template; |
24 | use phpbb\user; |
25 | |
26 | /** |
27 | * @ignore |
28 | */ |
29 | if (!defined('IN_PHPBB')) |
30 | { |
31 | exit; |
32 | } |
33 | |
34 | class acp_storage |
35 | { |
36 | /** @var driver_interface */ |
37 | protected $db; |
38 | |
39 | /** @var language */ |
40 | protected $lang; |
41 | |
42 | /** @var log_interface */ |
43 | protected $log; |
44 | |
45 | /** @var request */ |
46 | protected $request; |
47 | |
48 | /** @var template */ |
49 | protected $template; |
50 | |
51 | /** @var user */ |
52 | protected $user; |
53 | |
54 | /** @var service_collection */ |
55 | protected $provider_collection; |
56 | |
57 | /** @var service_collection */ |
58 | protected $storage_collection; |
59 | |
60 | /** @var \phpbb\filesystem\filesystem */ |
61 | protected $filesystem; |
62 | |
63 | /** @var string */ |
64 | public $page_title; |
65 | |
66 | /** @var string */ |
67 | public $phpbb_root_path; |
68 | |
69 | /** @var string */ |
70 | public $tpl_name; |
71 | |
72 | /** @var string */ |
73 | public $u_action; |
74 | |
75 | /** @var state_helper */ |
76 | private $state_helper; |
77 | |
78 | /** @var helper */ |
79 | private $storage_helper; |
80 | |
81 | /** @var string */ |
82 | private $storage_table; |
83 | |
84 | /** |
85 | * @param string $id |
86 | * @param string $mode |
87 | */ |
88 | public function main(string $id, string $mode): void |
89 | { |
90 | global $phpbb_container, $phpbb_dispatcher, $phpbb_root_path; |
91 | |
92 | $this->db = $phpbb_container->get('dbal.conn'); |
93 | $this->lang = $phpbb_container->get('language'); |
94 | $this->log = $phpbb_container->get('log'); |
95 | $this->request = $phpbb_container->get('request'); |
96 | $this->template = $phpbb_container->get('template'); |
97 | $this->user = $phpbb_container->get('user'); |
98 | $this->provider_collection = $phpbb_container->get('storage.provider_collection'); |
99 | $this->storage_collection = $phpbb_container->get('storage.storage_collection'); |
100 | $this->filesystem = $phpbb_container->get('filesystem'); |
101 | $this->phpbb_root_path = $phpbb_root_path; |
102 | $this->state_helper = $phpbb_container->get('storage.state_helper'); |
103 | $this->storage_helper = $phpbb_container->get('storage.helper'); |
104 | $this->storage_table = $phpbb_container->getParameter('tables.storage'); |
105 | |
106 | // Add necessary language files |
107 | $this->lang->add_lang(['acp/storage']); |
108 | |
109 | /** |
110 | * Add language strings |
111 | * |
112 | * @event core.acp_storage_load |
113 | * @since 4.0.0-a1 |
114 | */ |
115 | $phpbb_dispatcher->trigger_event('core.acp_storage_load'); |
116 | |
117 | switch ($mode) |
118 | { |
119 | case 'settings': |
120 | $this->settings($id, $mode); |
121 | break; |
122 | } |
123 | } |
124 | |
125 | /** |
126 | * Method to route the request to the correct page |
127 | * |
128 | * @param string $id |
129 | * @param string $mode |
130 | */ |
131 | private function settings(string $id, string $mode): void |
132 | { |
133 | $action = $this->request->variable('action', ''); |
134 | if ($action && !$this->request->is_set_post('cancel')) |
135 | { |
136 | switch ($action) |
137 | { |
138 | case 'update': |
139 | $this->update_action(); |
140 | break; |
141 | |
142 | default: |
143 | trigger_error('NO_ACTION', E_USER_ERROR); |
144 | } |
145 | } |
146 | else |
147 | { |
148 | // If clicked to cancel (acp_storage_update_progress form) |
149 | if ($this->request->is_set_post('cancel')) |
150 | { |
151 | $this->state_helper->clear_state(); |
152 | } |
153 | |
154 | // There is an updating in progress, show the form to continue or cancel |
155 | if ($this->state_helper->is_action_in_progress()) |
156 | { |
157 | $this->update_inprogress(); |
158 | } |
159 | else |
160 | { |
161 | $this->settings_form(); |
162 | } |
163 | } |
164 | } |
165 | |
166 | /** |
167 | * Page to update storage settings and move files |
168 | * |
169 | * @return void |
170 | */ |
171 | private function update_action(): void |
172 | { |
173 | if (!check_link_hash($this->request->variable('hash', ''), 'acp_storage')) |
174 | { |
175 | trigger_error($this->lang->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING); |
176 | } |
177 | |
178 | // If update_type is copy or move, copy files from the old to the new storage |
179 | if (in_array($this->state_helper->update_type(), [update_type::COPY, update_type::MOVE], true)) |
180 | { |
181 | $i = 0; |
182 | foreach ($this->state_helper->storages() as $storage_name) |
183 | { |
184 | // Skip storages that have already copied files |
185 | if ($this->state_helper->storage_index() > $i++) |
186 | { |
187 | continue; |
188 | } |
189 | |
190 | $sql = 'SELECT file_id, file_path |
191 | FROM ' . $this->storage_table . " |
192 | WHERE storage = '" . $this->db->sql_escape($storage_name) . "' |
193 | AND file_id > " . $this->state_helper->file_index(); |
194 | $result = $this->db->sql_query($sql); |
195 | |
196 | while ($row = $this->db->sql_fetchrow($result)) |
197 | { |
198 | if (!still_on_time()) |
199 | { |
200 | $this->db->sql_freeresult($result); |
201 | $this->display_progress_page(); |
202 | return; |
203 | } |
204 | |
205 | // Copy file from old adapter to the new one |
206 | $this->storage_helper->copy_file_to_new_adapter($storage_name, $row['file_path']); |
207 | |
208 | $this->state_helper->set_file_index($row['file_id']); // update last file index copied |
209 | } |
210 | |
211 | $this->db->sql_freeresult($result); |
212 | |
213 | // Copied all files of a storage, increase storage index and reset file index |
214 | $this->state_helper->set_storage_index($this->state_helper->storage_index()+1); |
215 | $this->state_helper->set_file_index(0); |
216 | } |
217 | |
218 | // If update_type is move files, remove the old files |
219 | if ($this->state_helper->update_type() === update_type::MOVE) |
220 | { |
221 | $i = 0; |
222 | foreach ($this->state_helper->storages() as $storage_name) |
223 | { |
224 | // Skip storages that have already moved files |
225 | if ($this->state_helper->remove_storage_index() > $i++) |
226 | { |
227 | continue; |
228 | } |
229 | |
230 | $sql = 'SELECT file_id, file_path |
231 | FROM ' . $this->storage_table . " |
232 | WHERE storage = '" . $this->db->sql_escape($storage_name) . "' |
233 | AND file_id > " . $this->state_helper->file_index(); |
234 | $result = $this->db->sql_query($sql); |
235 | |
236 | while ($row = $this->db->sql_fetchrow($result)) |
237 | { |
238 | if (!still_on_time()) |
239 | { |
240 | $this->db->sql_freeresult($result); |
241 | $this->display_progress_page(); |
242 | return; |
243 | } |
244 | |
245 | // remove file from old (current) adapter |
246 | $current_adapter = $this->storage_helper->get_current_adapter($storage_name); |
247 | $current_adapter->delete($row['file_path']); |
248 | |
249 | $this->state_helper->set_file_index($row['file_id']); |
250 | } |
251 | |
252 | $this->db->sql_freeresult($result); |
253 | |
254 | // Remove all files of a storage, increase storage index and reset file index |
255 | $this->state_helper->set_remove_storage_index($this->state_helper->remove_storage_index() + 1); |
256 | $this->state_helper->set_file_index(0); |
257 | } |
258 | } |
259 | } |
260 | |
261 | // Here all files have been copied/moved, so save new configuration |
262 | foreach ($this->state_helper->storages() as $storage_name) |
263 | { |
264 | $this->storage_helper->update_storage_config($storage_name); |
265 | } |
266 | |
267 | $storages = $this->state_helper->storages(); |
268 | $this->state_helper->clear_state(); |
269 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_STORAGE_UPDATE', false, [implode(', ', $storages)]); |
270 | trigger_error($this->lang->lang('STORAGE_UPDATE_SUCCESSFUL') . adm_back_link($this->u_action)); |
271 | } |
272 | |
273 | /** |
274 | * Page that show a form with the progress bar, and a button to continue or cancel |
275 | * |
276 | * @return void |
277 | */ |
278 | private function update_inprogress(): void |
279 | { |
280 | // Template from adm/style |
281 | $this->tpl_name = 'acp_storage_update_inprogress'; |
282 | |
283 | // Set page title |
284 | $this->page_title = 'STORAGE_TITLE'; |
285 | |
286 | $this->template->assign_vars([ |
287 | 'U_ACTION' => $this->u_action . '&action=update&hash=' . generate_link_hash('acp_storage'), |
288 | 'CONTINUE_PROGRESS' => $this->get_storage_update_progress(), |
289 | ]); |
290 | } |
291 | |
292 | /** |
293 | * Main settings page, shows a form with all the storages and their configuration options |
294 | * |
295 | * @return void |
296 | */ |
297 | private function settings_form(): void |
298 | { |
299 | $form_key = 'acp_storage'; |
300 | add_form_key($form_key); |
301 | |
302 | // Process form and create a "state" for the update, |
303 | // then show a confirm form |
304 | if ($this->request->is_set_post('submit')) |
305 | { |
306 | if (!check_form_key($form_key) || !check_link_hash($this->request->variable('hash', ''), 'acp_storage')) |
307 | { |
308 | trigger_error($this->lang->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING); |
309 | } |
310 | |
311 | $modified_storages = $this->get_modified_storages(); |
312 | |
313 | // validate submited paths if they are local |
314 | $messages = []; |
315 | foreach ($modified_storages as $storage_name) |
316 | { |
317 | $this->validate_data($storage_name, $messages); |
318 | } |
319 | if (!empty($messages)) |
320 | { |
321 | trigger_error(implode('<br>', $messages) . adm_back_link($this->u_action), E_USER_WARNING); |
322 | } |
323 | |
324 | // Start process and show progress |
325 | if (!empty($modified_storages)) |
326 | { |
327 | // Create state |
328 | $this->state_helper->init(update_type::from((int) $this->request->variable('update_type', update_type::CONFIG->value)), $modified_storages, $this->request); |
329 | |
330 | // Start displaying progress on first submit |
331 | $this->display_progress_page(); |
332 | return; |
333 | } |
334 | |
335 | // If there is no changes |
336 | trigger_error($this->lang->lang('STORAGE_NO_CHANGES') . adm_back_link($this->u_action), E_USER_WARNING); |
337 | } |
338 | |
339 | // Template from adm/style |
340 | $this->tpl_name = 'acp_storage'; |
341 | |
342 | // Set page title |
343 | $this->page_title = 'STORAGE_TITLE'; |
344 | |
345 | $this->storage_stats(); // Show table with storage stats |
346 | |
347 | // Validate local paths to check if everything is fine |
348 | $messages = []; |
349 | foreach ($this->storage_collection as $storage) |
350 | { |
351 | $this->validate_path($storage->get_name(), $messages); |
352 | } |
353 | |
354 | $this->template->assign_vars([ |
355 | 'STORAGES' => $this->storage_collection, |
356 | 'PROVIDERS' => $this->provider_collection, |
357 | |
358 | 'ERROR_MESSAGES' => $messages, |
359 | |
360 | 'U_ACTION' => $this->u_action . '&hash=' . generate_link_hash('acp_storage'), |
361 | |
362 | 'STORAGE_UPDATE_TYPE_CONFIG' => update_type::CONFIG->value, |
363 | 'STORAGE_UPDATE_TYPE_COPY' => update_type::COPY->value, |
364 | 'STORAGE_UPDATE_TYPE_MOVE' => update_type::MOVE->value, |
365 | ]); |
366 | } |
367 | |
368 | /** |
369 | * When submit the settings form, check which storages have been modified |
370 | * to update only those. |
371 | * |
372 | * @return array |
373 | */ |
374 | private function get_modified_storages(): array |
375 | { |
376 | $modified_storages = []; |
377 | |
378 | foreach ($this->storage_collection as $storage) |
379 | { |
380 | $storage_name = $storage->get_name(); |
381 | $options = $this->storage_helper->get_provider_options($this->storage_helper->get_current_provider($storage_name)); |
382 | |
383 | $modified = false; |
384 | |
385 | // Check if provider have been modified |
386 | if ($this->request->variable([$storage_name, 'provider'], '') != $this->storage_helper->get_current_provider($storage_name)) |
387 | { |
388 | $modified = true; |
389 | } |
390 | else |
391 | { |
392 | // Check if options have been modified |
393 | foreach (array_keys($options) as $definition) |
394 | { |
395 | if ($this->request->variable([$storage_name, $definition], '') != $this->storage_helper->get_current_definition($storage_name, $definition)) |
396 | { |
397 | $modified = true; |
398 | break; |
399 | } |
400 | } |
401 | } |
402 | |
403 | if ($modified) |
404 | { |
405 | $modified_storages[] = $storage_name; |
406 | } |
407 | } |
408 | |
409 | return $modified_storages; |
410 | } |
411 | |
412 | /** |
413 | * Fill template variables to show storage stats in settings page |
414 | * |
415 | * @return void |
416 | */ |
417 | protected function storage_stats(): void |
418 | { |
419 | // Top table with stats of each storage |
420 | $storage_stats = []; |
421 | foreach ($this->storage_collection as $storage) |
422 | { |
423 | try |
424 | { |
425 | $free_space = get_formatted_filesize($storage->free_space()); |
426 | } |
427 | catch (storage_exception $e) |
428 | { |
429 | $free_space = $this->lang->lang('STORAGE_UNKNOWN'); |
430 | } |
431 | |
432 | $storage_stats[] = [ |
433 | 'name' => $this->lang->lang('STORAGE_' . strtoupper($storage->get_name()) . '_TITLE'), |
434 | 'files' => $storage->get_num_files(), |
435 | 'size' => get_formatted_filesize($storage->get_size()), |
436 | 'free_space' => $free_space, |
437 | ]; |
438 | } |
439 | |
440 | $this->template->assign_vars([ |
441 | 'STORAGE_STATS' => $storage_stats, |
442 | ]); |
443 | } |
444 | |
445 | /** |
446 | * Display progress page |
447 | */ |
448 | protected function display_progress_page() : void |
449 | { |
450 | $u_action = append_sid($this->u_action . '&action=update&hash=' . generate_link_hash('acp_storage')); |
451 | meta_refresh(1, $u_action); |
452 | |
453 | adm_page_header($this->lang->lang('STORAGE_UPDATE_IN_PROGRESS')); |
454 | $this->template->set_filenames([ |
455 | 'body' => 'acp_storage_update_progress.html' |
456 | ]); |
457 | |
458 | $this->template->assign_vars([ |
459 | 'INDEXING_TITLE' => $this->lang->lang('STORAGE_UPDATE_IN_PROGRESS'), |
460 | 'INDEXING_EXPLAIN' => $this->lang->lang('STORAGE_UPDATE_IN_PROGRESS_EXPLAIN'), |
461 | 'INDEXING_PROGRESS_BAR' => $this->get_storage_update_progress(), |
462 | ]); |
463 | adm_page_footer(); |
464 | } |
465 | |
466 | /** |
467 | * Get storage update progress to show progress bar |
468 | * |
469 | * @return array |
470 | */ |
471 | protected function get_storage_update_progress(): array |
472 | { |
473 | $file_index = $this->state_helper->file_index(); |
474 | $stage_is_copy = $this->state_helper->storage_index() < count($this->state_helper->storages()); |
475 | $storage_name = $this->state_helper->storages()[$stage_is_copy ? $this->state_helper->storage_index() : $this->state_helper->remove_storage_index()]; |
476 | |
477 | $sql = 'SELECT COUNT(file_id) as done_count |
478 | FROM ' . $this->storage_table . ' |
479 | WHERE file_id <= ' . $file_index . " |
480 | AND storage = '" . $this->db->sql_escape($storage_name) . "'"; |
481 | $result = $this->db->sql_query($sql); |
482 | $done_count = (int) $this->db->sql_fetchfield('done_count'); |
483 | $this->db->sql_freeresult($result); |
484 | |
485 | $sql = 'SELECT COUNT(file_id) as remain_count |
486 | FROM ' . $this->storage_table . " |
487 | WHERE file_id > ' . $file_index . ' |
488 | AND storage = '" . $this->db->sql_escape($storage_name) . "'"; |
489 | $result = $this->db->sql_query($sql); |
490 | $remain_count = (int) $this->db->sql_fetchfield('remain_count'); |
491 | $this->db->sql_freeresult($result); |
492 | |
493 | $total_count = $done_count + $remain_count; |
494 | $percent = $total_count > 0 ? $done_count / $total_count : 0; |
495 | |
496 | $steps = $this->state_helper->storage_index() + $this->state_helper->remove_storage_index() + $percent; |
497 | $multiplier = $this->state_helper->update_type() === update_type::MOVE ? 2 : 1; |
498 | $steps_total = count($this->state_helper->storages()) * $multiplier; |
499 | |
500 | return [ |
501 | 'VALUE' => $steps, |
502 | 'TOTAL' => $steps_total, |
503 | 'PERCENTAGE' => $steps / $steps_total * 100, |
504 | ]; |
505 | } |
506 | |
507 | /** |
508 | * Validates data |
509 | * |
510 | * @param string $storage_name Storage name |
511 | * @param array $messages Reference to messages array |
512 | */ |
513 | protected function validate_data(string $storage_name, array &$messages): void |
514 | { |
515 | $storage_title = $this->lang->lang('STORAGE_' . strtoupper($storage_name) . '_TITLE'); |
516 | |
517 | // Check if provider exists |
518 | try |
519 | { |
520 | $new_provider = $this->provider_collection->get_by_class($this->request->variable([$storage_name, 'provider'], '')); |
521 | } |
522 | catch (\Exception $e) |
523 | { |
524 | $messages[] = $this->lang->lang('STORAGE_PROVIDER_NOT_EXISTS', $storage_title); |
525 | return; |
526 | } |
527 | |
528 | // Check if provider is available |
529 | if (!$new_provider->is_available()) |
530 | { |
531 | $messages[] = $this->lang->lang('STORAGE_PROVIDER_NOT_AVAILABLE', $storage_title); |
532 | return; |
533 | } |
534 | |
535 | $this->validate_path($storage_name, $messages); |
536 | |
537 | // Check options |
538 | $new_options = $this->storage_helper->get_provider_options($this->request->variable([$storage_name, 'provider'], '')); |
539 | |
540 | foreach ($new_options as $definition_key => $definition_value) |
541 | { |
542 | $provider = $this->provider_collection->get_by_class($this->request->variable([$storage_name, 'provider'], '')); |
543 | $definition_title = $this->lang->lang('STORAGE_ADAPTER_' . strtoupper($provider->get_name()) . '_OPTION_' . strtoupper($definition_key)); |
544 | |
545 | $value = $this->request->variable([$storage_name, $definition_key], ''); |
546 | |
547 | switch ($definition_value['tag']) |
548 | { |
549 | case 'text': |
550 | if ($definition_value['type'] == 'email' && filter_var($value, FILTER_VALIDATE_EMAIL)) |
551 | { |
552 | $messages[] = $this->lang->lang('STORAGE_FORM_TYPE_EMAIL_INCORRECT_FORMAT', $definition_title, $storage_title); |
553 | } |
554 | |
555 | $maxlength = $definition_value['max'] ?? 255; |
556 | if (strlen($value) > $maxlength) |
557 | { |
558 | $messages[] = $this->lang->lang('STORAGE_FORM_TYPE_TEXT_TOO_LONG', $definition_title, $storage_title); |
559 | } |
560 | |
561 | if ($provider->get_name() == 'local' && $definition_key == 'path') |
562 | { |
563 | $path = $value; |
564 | |
565 | if (empty($path)) |
566 | { |
567 | $messages[] = $this->lang->lang('STORAGE_PATH_NOT_SET', $this->lang->lang('STORAGE_' . strtoupper($storage_name) . '_TITLE')); |
568 | } |
569 | else if (!$this->filesystem->exists($this->phpbb_root_path . $path) || !$this->filesystem->is_writable($this->phpbb_root_path . $path)) |
570 | { |
571 | $messages[] = $this->lang->lang('STORAGE_PATH_NOT_EXISTS', $this->lang->lang('STORAGE_' . strtoupper($storage_name) . '_TITLE')); |
572 | } |
573 | } |
574 | break; |
575 | |
576 | case 'radio': |
577 | $found = false; |
578 | foreach ($definition_value['buttons'] as $button) |
579 | { |
580 | if ($button['value'] == $value) |
581 | { |
582 | $found = true; |
583 | break; |
584 | } |
585 | } |
586 | |
587 | if (!$found) |
588 | { |
589 | $messages[] = $this->lang->lang('STORAGE_FORM_TYPE_SELECT_NOT_AVAILABLE', $definition_title, $storage_title); |
590 | } |
591 | break; |
592 | |
593 | case 'select': |
594 | $found = false; |
595 | foreach ($definition_value['options'] as $option) |
596 | { |
597 | if ($option['value'] == $value) |
598 | { |
599 | $found = true; |
600 | break; |
601 | } |
602 | } |
603 | |
604 | if (!$found) |
605 | { |
606 | $messages[] = $this->lang->lang('STORAGE_FORM_TYPE_SELECT_NOT_AVAILABLE', $definition_title, $storage_title); |
607 | } |
608 | break; |
609 | } |
610 | } |
611 | } |
612 | |
613 | /** |
614 | * Validates path when the filesystem is local |
615 | * |
616 | * @param string $storage_name Storage name |
617 | * @param array $messages Error messages array |
618 | * @return void |
619 | */ |
620 | protected function validate_path(string $storage_name, array &$messages) : void |
621 | { |
622 | $current_provider = $this->storage_helper->get_current_provider($storage_name); |
623 | $options = $this->storage_helper->get_provider_options($current_provider); |
624 | |
625 | if ($this->provider_collection->get_by_class($current_provider)->get_name() == 'local' && isset($options['path'])) |
626 | { |
627 | $path = $this->request->is_set_post('submit') ? $this->request->variable([$storage_name, 'path'], '') : $this->storage_helper->get_current_definition($storage_name, 'path'); |
628 | |
629 | if (empty($path)) |
630 | { |
631 | $messages[] = $this->lang->lang('STORAGE_PATH_NOT_SET', $this->lang->lang('STORAGE_' . strtoupper($storage_name) . '_TITLE')); |
632 | } |
633 | else if (!$this->filesystem->exists($this->phpbb_root_path . $path) || !$this->filesystem->is_writable($this->phpbb_root_path . $path)) |
634 | { |
635 | $messages[] = $this->lang->lang('STORAGE_PATH_NOT_EXISTS', $this->lang->lang('STORAGE_' . strtoupper($storage_name) . '_TITLE')); |
636 | } |
637 | } |
638 | } |
639 | |
640 | } |