ILIAS  trunk Revision v12.0_alpha-1540-g00f839d5fa1
class.ilFileSystemGUI.php
Go to the documentation of this file.
1<?php
2
27use ILIAS\ResourceStorage\Preloader\SecureString;
28
35{
36 use SecureString; // This is just for those legacy classes which will be removed soon anyway.
37 public const PARAMETER_CDIR = "cdir";
38 public const SESSION_LAST_COMMAND = "fsys_lastcomm";
39 public const PARAMETER_NEWDIR = "newdir";
40 public const PARAMETER_FHSH = "fhsh";
41 public const POST_PARAM_FILE = "file";
42 public const PARAM_RESETOFFSET = "resetoffset";
43 public const PARAM_OLD_NAME = "old_name";
44 public const PARAM_UPFILE = "upfile";
45 public const POST_PARAM_NEW_NAME = "new_name";
46 public const POST_PARAM_NEW_DIR = "new_dir";
47 public const POST_PARAM_UPLOADED_FILE = "uploaded_file";
48 public const CMD_UNZIP_FILE = "unzipFile";
53 protected bool $use_upload_directory = false;
54 protected array $allowed_suffixes = [];
55 protected array $forbidden_suffixes = [];
56 protected ilLanguage $lng;
57 protected string $main_absolute_dir;
58 protected bool $post_dir_path = false;
60 protected array $file_labels = [];
61 protected bool $label_enable = false;
62 protected bool $allow_directories = true;
63 protected string $table_id = '';
64 protected string $title = '';
65 protected array $commands = [];
66 protected string $label_header = '';
67 protected bool $directory_creation = false;
68 protected bool $file_creation = false;
70 protected \ILIAS\Refinery\Factory $refinery;
71
75 public function __construct(string $main_absolute_directory)
76 {
77 global $DIC;
78
79 $this->ctrl = $DIC->ctrl();
80 $this->lng = $DIC->language();
81 $this->tpl = $DIC->ui()->mainTemplate();
82 $this->wrapper = $DIC->http()->wrapper();
83 $this->refinery = $DIC->refinery();
84 $this->main_absolute_dir = realpath($main_absolute_directory);
85 $this->ui_factory = $DIC->ui()->factory();
86 $this->ui_renderer = $DIC->ui()->renderer();
87 $this->unzip = $DIC->legacyArchives();
88
89 $this->defineCommands();
90
91 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
92 $this->lng->loadLanguageModule("content");
93 $this->setAllowDirectories(true);
94 $this->setAllowDirectoryCreation(true);
95 $this->setAllowFileCreation(true);
96 }
97
101 public function setAllowedSuffixes(array $a_suffixes): void
102 {
103 $this->allowed_suffixes = $a_suffixes;
104 }
105
109 public function getAllowedSuffixes(): array
110 {
112 }
113
117 public function setForbiddenSuffixes(array $a_suffixes): void
118 {
119 $this->forbidden_suffixes = $a_suffixes;
120 }
121
125 public function getForbiddenSuffixes(): array
126 {
128 }
129
130 public function isValidSuffix(string $a_suffix): bool
131 {
132 if (empty($a_suffix)) {
133 return true;
134 }
135
136 if (is_array($this->getForbiddenSuffixes()) && in_array($a_suffix, $this->getForbiddenSuffixes())) {
137 return false;
138 }
139 if (is_array($this->getAllowedSuffixes()) && in_array($a_suffix, $this->getAllowedSuffixes())) {
140 return true;
141 }
142 return !is_array($this->getAllowedSuffixes()) || count($this->getAllowedSuffixes()) == 0;
143 }
144
145 public function setAllowDirectories(bool $a_val): void
146 {
147 $this->allow_directories = $a_val;
148 }
149
150 public function getAllowDirectories(): bool
151 {
153 }
154
155 public function setPostDirPath(bool $a_val): void
156 {
157 $this->post_dir_path = $a_val;
158 }
159
160 public function getPostDirPath(): bool
161 {
163 }
164
165 public function setTableId(string $a_val): void
166 {
167 $this->table_id = $a_val;
168 }
169
170 public function getTableId(): string
171 {
172 return $this->table_id;
173 }
174
175 public function getMainAbsoluteDir(): string
176 {
178 }
179
180 public function setTitle(string $a_val): void
181 {
182 $this->title = $a_val;
183 }
184
185 public function getTitle(): string
186 {
187 return $this->title;
188 }
189
190 public function setUseUploadDirectory(bool $a_val): void
191 {
192 $this->use_upload_directory = $a_val;
193 }
194
195 public function getUseUploadDirectory(): bool
196 {
198 }
199
205 protected function setPerformedCommand($command, array $pars = []): void
206 {
207 if (!is_array($pars)) {
208 $pars = [];
209 }
210 ilSession::set(self::SESSION_LAST_COMMAND, array_merge(
211 ["cmd" => $command],
212 $pars
213 ));
214 }
215
219 public function getLastPerformedCommand(): array
220 {
221 if (!ilSession::has(self::SESSION_LAST_COMMAND)) {
222 return [];
223 }
224 $ret = ilSession::get(self::SESSION_LAST_COMMAND);
225 ilSession::set(self::SESSION_LAST_COMMAND, null);
226 return (array) $ret;
227 }
228
229 public function executeCommand(): string
230 {
231 $next_class = $this->ctrl->getNextClass($this);
232 $cmd = $this->ctrl->getCmd("listFiles");
233 if (str_starts_with((string) $cmd, "extCommand_")) {
234 $ret = $this->extCommand(substr((string) $cmd, 11, strlen((string) $cmd) - 11));
235 } else {
236 $ret = $this->$cmd();
237 }
238
239 return $ret ?? '';
240 }
241
242 public function addCommand(
243 object $a_obj,
244 string $a_func,
245 string $a_name,
246 bool $a_single = true,
247 bool $a_allow_dir = false
248 ): void {
249 $i = count($this->commands);
250
251 $this->commands[$i]["object"] = $a_obj;
252 $this->commands[$i]["method"] = $a_func;
253 $this->commands[$i]["name"] = $a_name;
254 $this->commands[$i]["single"] = $a_single;
255 $this->commands[$i]["allow_dir"] = $a_allow_dir;
256 }
257
258 public function clearCommands(): void
259 {
260 $this->commands = [];
261 }
262
263 public function labelFile(string $a_file, string $a_label): void
264 {
265 $this->file_labels[$a_file][] = $a_label;
266 }
267
268 public function activateLabels(bool $a_act, string $a_label_header): void
269 {
270 $this->label_enable = $a_act;
271 $this->label_header = $a_label_header;
272 }
273
277 protected function parseCurrentDirectory(): array
278 {
279 // determine directory
280 // FIXME: I have to call stripSlashes here twice, because I could not
281 // determine where the second layer of slashes is added to the
282 // URL Parameter
283
284 $cur_subdir = $this->wrapper->query()->has(self::PARAMETER_CDIR)
285 ? $this->wrapper->query()->retrieve(self::PARAMETER_CDIR, $this->refinery->to()->string())
286 : '';
287
288 $new_subdir = $this->wrapper->query()->has(self::PARAMETER_NEWDIR)
289 ? $this->wrapper->query()->retrieve(self::PARAMETER_NEWDIR, $this->refinery->to()->string())
290 : '';
291
292 $cur_subdir = ilUtil::stripSlashes(ilUtil::stripSlashes($cur_subdir));
293 $new_subdir = ilUtil::stripSlashes(ilUtil::stripSlashes($new_subdir));
294
295 if ($new_subdir === "..") {
296 $cur_subdir = substr($cur_subdir, 0, strrpos($cur_subdir, "/"));
297 } elseif (!empty($new_subdir)) {
298 $cur_subdir = empty($cur_subdir) ? $new_subdir : $cur_subdir . "/" . $new_subdir;
299 }
300
301 $cur_subdir = str_replace("..", "", $cur_subdir);
302 $cur_dir = (empty($cur_subdir))
303 ? $this->main_absolute_dir
304 : $this->main_absolute_dir . "/" . $cur_subdir;
305
306 $resolved_dir = realpath($cur_dir);
307 if ($resolved_dir === false) {
308 // The requested directory cannot be resolved, e.g. because its
309 // name contains non-UTF-8/special characters created by an older
310 // ILIAS version (Mantis 45045). Fall back to the managed base
311 // directory instead of crashing the whole page.
312 return [
313 "dir" => $this->main_absolute_dir,
314 "subdir" => ''
315 ];
316 }
317
318 return [
319 "dir" => $resolved_dir,
320 "subdir" => $cur_subdir
321 ];
322 }
323
327 protected function getFileList(string $a_dir, ?string $a_subdir = null): array
328 {
329 $items = [];
330
331 $entries = (is_dir($a_dir))
332 ? ilFileUtils::getDir($a_dir)
333 : [["type" => "dir", "entry" => ".."]];
334
335 $items = [];
336 foreach ($entries as $e) {
337 if ($e["entry"] == ".") {
338 continue;
339 }
340 if ($e["entry"] == ".." && empty($a_subdir)) {
341 continue;
342 }
343 $cfile = (empty($a_subdir))
344 ? $e["entry"]
345 : $a_subdir . "/" . $e["entry"];
346
347 $items[] = [
348 self::POST_PARAM_FILE => $cfile,
349 "entry" => $e["entry"],
350 "type" => $e["type"],
351 "size" => $e["size"] ?? 0,
352 "hash" => md5((string) $e["entry"])
353 ];
354 }
355
356 return $items;
357 }
358
362 protected function getIncomingFiles(): array
363 {
364 $sel_files = $hashes = [];
365 if ($this->wrapper->post()->has(self::POST_PARAM_FILE)) {
366 $hashes = $this->wrapper->post()->retrieve(
367 self::POST_PARAM_FILE,
368 $this->refinery->to()->listOf(
369 $this->refinery->to()->string()
370 )
371 );
372 } elseif ($this->wrapper->query()->has(self::PARAMETER_FHSH)) {
373 $hashes = [$this->wrapper->query()->retrieve(
374 self::PARAMETER_FHSH,
375 $this->refinery->to()->string()
376 )
377 ];
378 }
379
380 if (count($hashes) > 0) {
381 $dir = $this->parseCurrentDirectory();
382 $all_files = $this->getFileList($dir["dir"], $dir["subdir"]);
383 foreach ($hashes as $hash) {
384 foreach ($all_files as $file) {
385 if ($file["hash"] == $hash) {
386 $sel_files[] = $this->getPostDirPath()
387 ? $file[self::POST_PARAM_FILE]
388 : $file["entry"];
389 break;
390 }
391 }
392 }
393 }
394
395 return $sel_files;
396 }
397
398 private function extCommand(int $a_nr): string
399 {
400 $selected = $this->getIncomingFiles();
401
402 if ($selected === []) {
403 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
404 $this->ctrl->redirect($this, "listFiles");
405 }
406
407 // check if only one item is select, if command does not allow multiple selection
408 if (count($selected) > 1 && ($this->commands[$a_nr]["single"] ?? false)) {
409 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("cont_select_max_one_item"), true);
410 $this->ctrl->redirect($this, "listFiles");
411 }
412
413 $cur_subdir = $this->sanitizeCurrentDirectory();
414
415 // collect files and
416 $files = [];
417 foreach ($selected as $file) {
418 $file = ilUtil::stripSlashes($file);
419 $file = (empty($cur_subdir))
420 ? $file
421 : $cur_subdir . "/" . $file;
422
423 // check wether selected item is a directory
424 if (is_dir($this->main_absolute_dir . "/" . $file) &&
425 !$this->commands[$a_nr]["allow_dir"]) {
426 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("select_a_file"), true);
427 $this->ctrl->redirect($this, "listFiles");
428 }
429
430 $files[] = $file;
431 }
432
433 if ($this->commands[$a_nr]["single"] ?? false) {
434 $files = array_shift($files);
435 }
436
437 $obj = $this->commands[$a_nr]["object"];
438 $method = $this->commands[$a_nr]["method"];
439
440 return (string) $obj->$method($files);
441 }
442
443 public function setAllowDirectoryCreation(bool $a_val): void
444 {
445 $this->directory_creation = $a_val;
446 }
447
448 public function getAllowDirectoryCreation(): bool
449 {
450 return $this->directory_creation;
451 }
452
456 public function setAllowFileCreation(bool $a_val): void
457 {
458 $this->file_creation = $a_val;
459 }
460
461 public function getAllowFileCreation(): bool
462 {
463 return $this->file_creation;
464 }
465
466 public function listFiles(?ilTable2GUI $a_table_gui = null): void
467 {
468 global $DIC;
469 $ilToolbar = $DIC['ilToolbar'];
470 $lng = $DIC['lng'];
471 $ilCtrl = $DIC['ilCtrl'];
472
473 $dir = $this->parseCurrentDirectory();
474
475 $this->ctrl->setParameter($this, self::PARAMETER_CDIR, $dir["subdir"]);
476
477 // toolbar for adding files/directories
478 $ilToolbar->setFormAction($ilCtrl->getFormAction($this), true);
479
480 if ($this->getAllowDirectories() && $this->getAllowDirectoryCreation()) {
481 $ti = new ilTextInputGUI($this->lng->txt("cont_new_dir"), self::POST_PARAM_NEW_DIR);
482 $ti->setMaxLength(80);
483 $ti->setSize(10);
484 $ilToolbar->addInputItem($ti, true);
485 $ilToolbar->addFormButton($lng->txt("create"), "createDirectory");
486
487 $ilToolbar->addSeparator();
488 }
489 if ($this->getAllowFileCreation()) {
490 $fi = new ilFileInputGUI($this->lng->txt("cont_new_file"), "new_file");
491 $fi->setSize(10);
492 $ilToolbar->addInputItem($fi, true);
493 $ilToolbar->addFormButton($lng->txt("upload"), "uploadFile");
494 }
495 if (ilUploadFiles::_getUploadDirectory() && $this->getAllowFileCreation() && $this->getUseUploadDirectory()) {
496 $ilToolbar->addSeparator();
498 $options[""] = $lng->txt("cont_select_from_upload_dir");
499 foreach ($files as $file) {
500 $file = htmlspecialchars($file, ENT_QUOTES, "utf-8");
501 $options[$file] = $file;
502 }
503 $si = new ilSelectInputGUI($this->lng->txt("cont_uploaded_file"), self::POST_PARAM_UPLOADED_FILE);
504 $si->setOptions($options);
505 $ilToolbar->addInputItem($si, true);
506 $ilToolbar->addFormButton($lng->txt("copy"), "uploadFile");
507 }
508
509 $fs_table = $this->getTable($dir["dir"], $dir["subdir"]);
510
511 if ($this->getTitle() !== "") {
512 $fs_table->setTitle($this->getTitle());
513 }
514 if (
515 $this->wrapper->query()->has(self::PARAM_RESETOFFSET)
516 && $this->wrapper->query()->retrieve(
517 self::PARAM_RESETOFFSET,
518 $this->refinery->kindlyTo()->int()
519 ) == 1) {
520 $fs_table->resetOffset();
521 }
522 $this->tpl->setContent($fs_table->getHTML());
523 }
524
525 public function getTable(string $a_dir, string $a_subdir): \ilFileSystemTableGUI
526 {
527 return new ilFileSystemTableGUI(
528 $this,
529 "listFiles",
530 $a_dir,
531 $a_subdir,
532 $this->label_enable,
533 $this->file_labels,
534 $this->label_header,
535 $this->commands,
536 $this->getPostDirPath(),
537 $this->getTableId()
538 );
539 }
540
541 public function renameFileForm(string $a_file): void
542 {
543 $cur_subdir = $this->sanitizeCurrentDirectory();
544 $file = $this->main_absolute_dir . "/" . $a_file;
545
546 $this->ctrl->setParameter($this, self::PARAM_OLD_NAME, basename($a_file));
547 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
548 $form = new ilPropertyFormGUI();
549
550 // file/dir name
551 $ti = new ilTextInputGUI($this->lng->txt("name"), self::POST_PARAM_NEW_NAME);
552 $ti->setMaxLength(200);
553 $ti->setSize(40);
554 $ti->setValue(basename($a_file));
555 $form->addItem($ti);
556
557 // save and cancel commands
558 $form->addCommandButton("renameFile", $this->lng->txt("rename"));
559 $form->addCommandButton("cancelRename", $this->lng->txt("cancel"));
560 $form->setFormAction($this->ctrl->getFormAction($this, "renameFile"));
561
562 if (is_dir($file)) {
563 $form->setTitle($this->lng->txt("cont_rename_dir"));
564 } else {
565 $form->setTitle($this->lng->txt("rename_file"));
566 }
567
568 $this->tpl->setContent($form->getHTML());
569 }
570
571 public function renameFile(): void
572 {
573 $new_name = $this->wrapper->post()->has(self::POST_PARAM_NEW_NAME)
574 ? $this->wrapper->post()->retrieve(self::POST_PARAM_NEW_NAME, $this->refinery->to()->string())
575 : '';
576
577 $new_name = str_replace("..", "", ilUtil::stripSlashes($new_name));
578 $new_name = str_replace("/", "", $new_name);
579 if ($new_name === "") {
580 throw new LogicException($this->lng->txt("enter_new_name"));
581 }
582
583 $pi = pathinfo($new_name);
584 $suffix = $pi["extension"] ?? "";
585 if ($suffix != "" && !$this->isValidSuffix($suffix)) {
586 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("file_no_valid_file_type") . " ($suffix)", true);
587 $this->ctrl->redirect($this, "listFiles");
588 }
589
590 $cur_subdir = $this->sanitizeCurrentDirectory();
591 $dir = (empty($cur_subdir))
592 ? $this->main_absolute_dir . "/"
593 : $this->main_absolute_dir . "/" . $cur_subdir . "/";
594
595 $old_name = $this->wrapper->query()->has(self::PARAM_OLD_NAME)
596 ? $this->wrapper->query()->retrieve(self::PARAM_OLD_NAME, $this->refinery->to()->string())
597 : null;
598
599 // check if this path is inside $dir
600 $old_name = ilUtil::stripSlashes($old_name);
601 $realpath = realpath($dir . $old_name);
602 if (!str_starts_with($realpath, realpath($dir))) {
603 throw new ilException($this->lng->txt("no_permission"));
604 }
605
606 if (is_dir($dir . $old_name)) {
607 rename($dir . $old_name, $dir . $new_name);
608 } else {
609 try {
610 ilFileUtils::rename($dir . $old_name, $dir . $new_name);
611 } catch (ilException $e) {
612 $this->tpl->setOnScreenMessage('failure', $e->getMessage(), true);
613 $this->ctrl->redirect($this, "listFiles");
614 }
615 }
616
617 ilFileUtils::renameExecutables($this->main_absolute_dir);
618 if (is_dir($dir . $new_name)) {
619 $this->tpl->setOnScreenMessage(
620 'success',
621 $this->lng->txt("cont_dir_renamed"),
622 true
623 );
624 $this->setPerformedCommand("rename_dir", [self::PARAM_OLD_NAME => $old_name,
625 self::POST_PARAM_NEW_NAME => $new_name
626 ]);
627 } else {
628 $this->tpl->setOnScreenMessage(
629 'success',
630 $this->lng->txt("cont_file_renamed"),
631 true
632 );
633 $this->setPerformedCommand("rename_file", [self::PARAM_OLD_NAME => $old_name,
634 self::POST_PARAM_NEW_NAME => $new_name
635 ]);
636 }
637 $this->ctrl->redirect($this, "listFiles");
638 }
639
640 public function cancelRename(): void
641 {
642 $this->ctrl->redirect($this, "listFiles");
643 }
644
645 public function createDirectory(): void
646 {
647 global $DIC;
648 $lng = $DIC['lng'];
649
650 // determine directory
651 $cur_subdir = $this->sanitizeCurrentDirectory();
652 $cur_dir = (empty($cur_subdir))
653 ? $this->main_absolute_dir
654 : $this->main_absolute_dir . "/" . $cur_subdir;
655
656 $new_dir = $this->wrapper->post()->has(self::POST_PARAM_NEW_DIR)
657 ? $this->wrapper->post()->retrieve(self::POST_PARAM_NEW_DIR, $this->refinery->to()->string())
658 : '';
659
660 $new_dir = str_replace(".", "", ilUtil::stripSlashes($new_dir));
661 $new_dir = str_replace("/", "", $new_dir);
662
663 if (!empty($new_dir)) {
664 ilFileUtils::makeDir($cur_dir . "/" . $new_dir);
665 if (is_dir($cur_dir . "/" . $new_dir)) {
666 $this->tpl->setOnScreenMessage('success', $lng->txt("cont_dir_created"), true);
667 $this->setPerformedCommand("create_dir", ["name" => $new_dir]);
668 }
669 } else {
670 $this->tpl->setOnScreenMessage('failure', $lng->txt("cont_enter_a_dir_name"), true);
671 }
672 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
673 $this->ctrl->redirect($this, 'listFiles');
674 }
675
676 public function uploadFile(): void
677 {
678 global $DIC;
679 $lng = $DIC['lng'];
680
681 // determine directory
682 $cur_subdir = $this->sanitizeCurrentDirectory();
683 $cur_dir = (empty($cur_subdir))
684 ? $this->main_absolute_dir
685 : $this->main_absolute_dir . "/" . $cur_subdir;
686
687 $tgt_file = null;
688
689 $pi = pathinfo((string) $_FILES["new_file"]["name"]);
690 $suffix = $pi["extension"] ?? "";
691 if (!$this->isValidSuffix($suffix)) {
692 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("file_no_valid_file_type") . " ($suffix)", true);
693 $this->ctrl->redirect($this, "listFiles");
694 }
695
696 $uploaded_file = $this->wrapper->post()->has(self::POST_PARAM_UPLOADED_FILE)
697 ? $this->wrapper->post()->retrieve(self::POST_PARAM_UPLOADED_FILE, $this->refinery->to()->string())
698 : '';
699 if (is_file($_FILES["new_file"]["tmp_name"])) {
700 $name = $this->secure(ilUtil::stripSlashes($_FILES["new_file"]["name"]));
701 $tgt_file = $cur_dir . "/" . $name;
702
703 // use filesystem directly
704 //ilFileUtils::moveUploadedFile(, $name, $tgt_file);
705 $upload = $DIC->upload();
706
707 // If the upload has not yet been processed make sure he gets processed now.
708 if (!$upload->hasBeenProcessed()) {
709 $upload->process();
710 }
711
712
713 if (!$upload->hasUploads()) {
714 throw new ilException(
715 $DIC->language()->txt("upload_error_file_not_found")
716 );
717 }
718 $upload_result = $upload->getResults()[$_FILES["new_file"]["tmp_name"]];
719 if ($upload_result instanceof UploadResult) {
720 $processing_status = $upload_result->getStatus();
721 if ($processing_status->getCode() === ProcessingStatus::REJECTED) {
722 $this->tpl->setOnScreenMessage(
723 'failure',
724 $processing_status->getMessage(),
725 true
726 );
727 $this->ctrl->redirect($this, "listFiles");
728 }
729 }
730
731 $upload->moveOneFileTo(
732 $upload_result,
733 LegacyPathHelper::createRelativePath($cur_dir . "/"),
734 LegacyPathHelper::deriveLocationFrom($cur_dir),
735 $name,
736 true
737 );
738 // end upload
739 } elseif ($uploaded_file) {
740 // check if the file is in the ftp directory and readable
741 if (ilUploadFiles::_checkUploadFile($uploaded_file)) {
742 $tgt_file = $cur_dir . "/" . ilUtil::stripSlashes($uploaded_file);
743
744 // copy uploaded file to data directory
745 ilUploadFiles::_copyUploadFile($uploaded_file, $tgt_file);
746 }
747 } elseif (trim((string) $_FILES["new_file"]["name"]) === "") {
748 $this->tpl->setOnScreenMessage('failure', $lng->txt("cont_enter_a_file"), true);
749 }
750
751 if ($tgt_file && is_file($tgt_file)) {
752 $unzip = null;
753 if (MimeType::getMimeType($tgt_file) === "application/zip") {
754 $this->ctrl->setParameter($this, self::PARAM_UPFILE, basename($tgt_file));
755 $url = $this->ctrl->getLinkTarget($this, self::CMD_UNZIP_FILE);
756 $this->ctrl->setParameter($this, self::PARAM_UPFILE, "");
757
758 $unzip_link = $this->ui_factory->link()->standard(
759 $this->lng->txt("unzip"),
760 $url
761 );
762
763 $unzip = " " . $this->ui_renderer->render($unzip_link);
764 }
765
766 $this->tpl->setOnScreenMessage('success', $lng->txt("cont_file_created") . $unzip, true);
767
768 $this->setPerformedCommand(
769 "create_file",
770 ["name" => substr($tgt_file, strlen($this->main_absolute_dir) + 1)]
771 );
772 }
773
774 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
775
776 ilFileUtils::renameExecutables($this->main_absolute_dir);
777
778 $this->ctrl->redirect($this, 'listFiles');
779 }
780
781 public function confirmDeleteFile(array $a_files): void
782 {
783 global $DIC;
784 $ilCtrl = $DIC['ilCtrl'];
785 $tpl = $DIC['tpl'];
786 $lng = $DIC['lng'];
787
788 $cgui = new ilConfirmationGUI();
789 $cgui->setFormAction($ilCtrl->getFormAction($this));
790 $cgui->setHeaderText($lng->txt("info_delete_sure"));
791 $cgui->setCancel($lng->txt("cancel"), "listFiles");
792 $cgui->setConfirm($lng->txt("delete"), "deleteFile");
793
794 foreach ($a_files as $i) {
795 $cgui->addItem("file[]", $i, $i);
796 }
797
798 $tpl->setContent($cgui->getHTML());
799 }
800
801 public function deleteFile(): void
802 {
803 if (!$this->wrapper->post()->has(self::POST_PARAM_FILE)) {
804 throw new LogicException($this->lng->txt("no_checkbox"));
805 }
806 $is_dir = false;
807 $post_file = null;
808
809 $postfiles = $this->wrapper->post()->retrieve(
810 self::POST_PARAM_FILE,
811 $this->refinery->to()->listOf(
812 $this->refinery->to()->string()
813 )
814 );
815 foreach ($postfiles as $post_file) {
816 if (ilUtil::stripSlashes($post_file) === "..") {
817 throw new LogicException($this->lng->txt("no_checkbox"));
818 break;
819 }
820
821 $cur_subdir = $this->sanitizeCurrentDirectory();
822 $cur_dir = (empty($cur_subdir))
823 ? $this->main_absolute_dir
824 : $this->main_absolute_dir . "/" . $cur_subdir;
825 $pi = pathinfo((string) $post_file);
826 $file = $cur_dir . "/" . ilUtil::stripSlashes($pi["basename"]);
827
828 if (is_file($file)) {
829 unlink($file);
830 }
831
832 if (is_dir($file)) {
833 $is_dir = true;
834 ilFileUtils::delDir($file);
835 }
836 }
837
838 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
839 if ($is_dir) {
840 $this->tpl->setOnScreenMessage('success', $this->lng->txt("cont_dir_deleted"), true);
841 $this->setPerformedCommand(
842 "delete_dir",
843 ["name" => ilUtil::stripSlashes($post_file)]
844 );
845 } else {
846 $this->tpl->setOnScreenMessage('success', $this->lng->txt("cont_file_deleted"), true);
847 $this->setPerformedCommand(
848 "delete_file",
849 ["name" => ilUtil::stripSlashes($post_file)]
850 );
851 }
852 $this->ctrl->redirect($this, 'listFiles');
853 }
854
855 public function unzipFile(?string $a_file = null): void
856 {
857 // #17470 - direct unzip call (after upload)
858 $upname = $this->wrapper->query()->has(self::PARAM_UPFILE)
859 ? $this->wrapper->query()->retrieve(self::PARAM_UPFILE, $this->refinery->to()->string())
860 : null;
861 if (is_null($a_file) && $upname !== null) {
862 $a_file = basename((string) $upname);
863 }
864
865 $cur_subdir = $this->sanitizeCurrentDirectory();
866 $cur_dir = (empty($cur_subdir))
867 ? $this->main_absolute_dir
868 : $this->main_absolute_dir . "/" . $cur_subdir;
869 $a_file = $this->main_absolute_dir . "/" . $a_file;
870
871 if (is_file($a_file)) {
872 $cur_files = array_keys(ilFileUtils::getDir($cur_dir));
873 $cur_files_r = iterator_to_array(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($cur_dir)));
874
875 $this->unzip->unzip(
876 $a_file,
877 null,
878 true,
879 !$this->getAllowDirectories(),
880 false
881 );
882
883 $new_files = array_keys(ilFileUtils::getDir($cur_dir));
884 $new_files_r = iterator_to_array(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($cur_dir)));
885
886 $diff = array_diff($new_files, $cur_files);
887 $diff_r = array_diff($new_files_r, $cur_files_r);
888
889 // unlink forbidden file types
890 foreach (array_keys($diff_r) as $f) {
891 $pi = pathinfo($f);
892 if (!is_dir($f) && !$this->isValidSuffix(strtolower($pi["extension"] ?? ''))) {
893 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("file_some_invalid_file_types_removed") . " (" . $pi["extension"] . ")", true);
894 unlink($f);
895 }
896 }
897
898 if ($diff !== []) {
899 if ($this->getAllowDirectories()) {
900 $new_files = [];
901
902 foreach ($diff as $new_item) {
903 if (is_dir($cur_dir . "/" . $new_item)) {
904 ilFileUtils::recursive_dirscan($cur_dir . "/" . $new_item, $new_files);
905 }
906 }
907
908 if (isset($new_files["path"])) {
909 foreach ($new_files["path"] as $idx => $path) {
910 $path = substr((string) $path, strlen($this->main_absolute_dir) + 1);
911 $diff[] = $path . $new_files[self::POST_PARAM_FILE][$idx];
912 }
913 }
914 }
915
916 $this->setPerformedCommand(
917 "unzip_file",
918 ["added" => $diff
919 ]
920 );
921 }
922 }
923
924 ilFileUtils::renameExecutables($this->main_absolute_dir);
925
926 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
927 $this->tpl->setOnScreenMessage('success', $this->lng->txt("cont_file_unzipped"), true);
928 $this->ctrl->redirect($this, "listFiles");
929 }
930
931 public function downloadFile(string $a_file): void
932 {
933 $file = $this->main_absolute_dir . "/" . $a_file;
934
935 if (is_file($file) && !(is_dir($file))) {
936 ilFileDelivery::deliverFileLegacy($file, basename($a_file));
937 exit;
938 }
939 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
940 $this->ctrl->redirect($this, "listFiles");
941 }
942
946 public function getActionCommands(): array
947 {
948 return $this->commands;
949 }
950
951 public function defineCommands(): void
952 {
953 $this->commands = [
954 0 => [
955 "object" => $this,
956 "method" => "downloadFile",
957 "name" => $this->lng->txt("download"),
958 "int" => true,
959 "single" => true
960 ],
961 1 => [
962 "object" => $this,
963 "method" => "confirmDeleteFile",
964 "name" => $this->lng->txt("delete"),
965 "allow_dir" => true,
966 "int" => true
967 ],
968 2 => [
969 "object" => $this,
970 "method" => self::CMD_UNZIP_FILE,
971 "name" => $this->lng->txt("unzip"),
972 "allow_dir" => true,
973 "int" => true,
974 "single" => true
975 ],
976 3 => [
977 "object" => $this,
978 "method" => "renameFileForm",
979 "name" => $this->lng->txt("rename"),
980 "allow_dir" => true,
981 "int" => true,
982 "single" => true
983 ],
984 ];
985 }
986
987 private function sanitizeCurrentDirectory(): string
988 {
989 $cur_subdir = $this->wrapper->query()->has(self::PARAMETER_CDIR)
990 ? $this->wrapper->query()->retrieve(self::PARAMETER_CDIR, $this->refinery->to()->string())
991 : '';
992
993 return str_replace(
994 "..",
995 "",
996 ilUtil::stripSlashes($cur_subdir)
997 );
998 }
999}
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Mime type determination.
Definition: MimeType.php:30
The legacy path helper provides convenient functions for the integration of the filesystem service wi...
return true
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Base class for ILIAS Exception handling.
static deliverFileLegacy(string $a_file, ?string $a_filename=null, ?string $a_mime=null, ?bool $isInline=false, ?bool $removeAfterDelivery=false, ?bool $a_exit_after=true)
This class represents a file property in a property form.
File System Explorer GUI class.
setAllowedSuffixes(array $a_suffixes)
activateLabels(bool $a_act, string $a_label_header)
ilCtrlInterface $ctrl
confirmDeleteFile(array $a_files)
listFiles(?ilTable2GUI $a_table_gui=null)
setForbiddenSuffixes(array $a_suffixes)
__construct(string $main_absolute_directory)
ilGlobalTemplateInterface $tpl
addCommand(object $a_obj, string $a_func, string $a_name, bool $a_single=true, bool $a_allow_dir=false)
labelFile(string $a_file, string $a_label)
getTable(string $a_dir, string $a_subdir)
setPerformedCommand($command, array $pars=[])
setAllowFileCreation(bool $a_val)
Set allowed file creation.
setAllowDirectoryCreation(bool $a_val)
unzipFile(?string $a_file=null)
setTableId(string $a_val)
downloadFile(string $a_file)
getFileList(string $a_dir, ?string $a_subdir=null)
setUseUploadDirectory(bool $a_val)
setAllowDirectories(bool $a_val)
isValidSuffix(string $a_suffix)
WrapperFactory $wrapper
ILIAS Refinery Factory $refinery
renameFileForm(string $a_file)
static getDir(string $a_dir, bool $a_rec=false, ?string $a_sub_dir="")
get directory
static recursive_dirscan(string $dir, array &$arr)
Recursively scans a given directory and writes path and filename into referenced array.
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
static rename(string $a_source, string $a_target)
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static renameExecutables(string $a_dir)
language handling
This class represents a property form user interface.
This class represents a selection list property in a property form.
static get(string $a_var)
static set(string $a_var, $a_val)
Set a value.
static has($a_var)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a text property in a property form.
static _copyUploadFile(string $a_file, string $a_target, bool $a_raise_errors=true)
static _checkUploadFile(string $a_file)
static _getUploadDirectory()
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
exit
setContent(string $a_html)
Sets content for standard template.
This is how the factory for UI elements looks.
Definition: Factory.php:38
An entity that renders components to a string output.
Definition: Renderer.php:31
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$path
Definition: ltiservices.php:30
global $lng
Definition: privfeed.php:26
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:70