ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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 setTitle(string $a_val): void
176 {
177 $this->title = $a_val;
178 }
179
180 public function getTitle(): string
181 {
182 return $this->title;
183 }
184
185 public function setUseUploadDirectory(bool $a_val): void
186 {
187 $this->use_upload_directory = $a_val;
188 }
189
190 public function getUseUploadDirectory(): bool
191 {
193 }
194
200 protected function setPerformedCommand($command, array $pars = []): void
201 {
202 if (!is_array($pars)) {
203 $pars = [];
204 }
205 ilSession::set(self::SESSION_LAST_COMMAND, array_merge(
206 ["cmd" => $command],
207 $pars
208 ));
209 }
210
214 public function getLastPerformedCommand(): array
215 {
216 if (!ilSession::has(self::SESSION_LAST_COMMAND)) {
217 return [];
218 }
219 $ret = ilSession::get(self::SESSION_LAST_COMMAND);
220 ilSession::set(self::SESSION_LAST_COMMAND, null);
221 return (array) $ret;
222 }
223
224 public function executeCommand(): string
225 {
226 $next_class = $this->ctrl->getNextClass($this);
227 $cmd = $this->ctrl->getCmd("listFiles");
228 if (str_starts_with((string) $cmd, "extCommand_")) {
229 $ret = $this->extCommand(substr((string) $cmd, 11, strlen((string) $cmd) - 11));
230 } else {
231 $ret = $this->$cmd();
232 }
233
234 return $ret ?? '';
235 }
236
237 public function addCommand(
238 object $a_obj,
239 string $a_func,
240 string $a_name,
241 bool $a_single = true,
242 bool $a_allow_dir = false
243 ): void {
244 $i = count($this->commands);
245
246 $this->commands[$i]["object"] = $a_obj;
247 $this->commands[$i]["method"] = $a_func;
248 $this->commands[$i]["name"] = $a_name;
249 $this->commands[$i]["single"] = $a_single;
250 $this->commands[$i]["allow_dir"] = $a_allow_dir;
251 }
252
253 public function clearCommands(): void
254 {
255 $this->commands = [];
256 }
257
258 public function labelFile(string $a_file, string $a_label): void
259 {
260 $this->file_labels[$a_file][] = $a_label;
261 }
262
263 public function activateLabels(bool $a_act, string $a_label_header): void
264 {
265 $this->label_enable = $a_act;
266 $this->label_header = $a_label_header;
267 }
268
272 protected function parseCurrentDirectory(): array
273 {
274 // determine directory
275 // FIXME: I have to call stripSlashes here twice, because I could not
276 // determine where the second layer of slashes is added to the
277 // URL Parameter
278
279 $cur_subdir = $this->wrapper->query()->has(self::PARAMETER_CDIR)
280 ? $this->wrapper->query()->retrieve(self::PARAMETER_CDIR, $this->refinery->to()->string())
281 : '';
282
283 $new_subdir = $this->wrapper->query()->has(self::PARAMETER_NEWDIR)
284 ? $this->wrapper->query()->retrieve(self::PARAMETER_NEWDIR, $this->refinery->to()->string())
285 : '';
286
287 $cur_subdir = ilUtil::stripSlashes(ilUtil::stripSlashes($cur_subdir));
288 $new_subdir = ilUtil::stripSlashes(ilUtil::stripSlashes($new_subdir));
289
290 if ($new_subdir === "..") {
291 $cur_subdir = substr($cur_subdir, 0, strrpos($cur_subdir, "/"));
292 } elseif (!empty($new_subdir)) {
293 $cur_subdir = empty($cur_subdir) ? $new_subdir : $cur_subdir . "/" . $new_subdir;
294 }
295
296 $cur_subdir = str_replace("..", "", $cur_subdir);
297 $cur_dir = (empty($cur_subdir))
298 ? $this->main_absolute_dir
299 : $this->main_absolute_dir . "/" . $cur_subdir;
300
301 return [
302 "dir" => realpath($cur_dir),
303 "subdir" => $cur_subdir
304 ];
305 }
306
310 protected function getFileList(string $a_dir, ?string $a_subdir = null): array
311 {
312 $items = [];
313
314 $entries = (is_dir($a_dir))
315 ? ilFileUtils::getDir($a_dir)
316 : [["type" => "dir", "entry" => ".."]];
317
318 $items = [];
319 foreach ($entries as $e) {
320 if ($e["entry"] == ".") {
321 continue;
322 }
323 if ($e["entry"] == ".." && empty($a_subdir)) {
324 continue;
325 }
326 $cfile = (empty($a_subdir))
327 ? $e["entry"]
328 : $a_subdir . "/" . $e["entry"];
329
330 $items[] = [
331 self::POST_PARAM_FILE => $cfile,
332 "entry" => $e["entry"],
333 "type" => $e["type"],
334 "size" => $e["size"] ?? 0,
335 "hash" => md5((string) $e["entry"])
336 ];
337 }
338
339 return $items;
340 }
341
345 protected function getIncomingFiles(): array
346 {
347 $sel_files = $hashes = [];
348 if ($this->wrapper->post()->has(self::POST_PARAM_FILE)) {
349 $hashes = $this->wrapper->post()->retrieve(
350 self::POST_PARAM_FILE,
351 $this->refinery->to()->listOf(
352 $this->refinery->to()->string()
353 )
354 );
355 } elseif ($this->wrapper->query()->has(self::PARAMETER_FHSH)) {
356 $hashes = [$this->wrapper->query()->retrieve(
357 self::PARAMETER_FHSH,
358 $this->refinery->to()->string()
359 )
360 ];
361 }
362
363 if (count($hashes) > 0) {
364 $dir = $this->parseCurrentDirectory();
365 $all_files = $this->getFileList($dir["dir"], $dir["subdir"]);
366 foreach ($hashes as $hash) {
367 foreach ($all_files as $file) {
368 if ($file["hash"] == $hash) {
369 $sel_files[] = $this->getPostDirPath()
370 ? $file[self::POST_PARAM_FILE]
371 : $file["entry"];
372 break;
373 }
374 }
375 }
376 }
377
378 return $sel_files;
379 }
380
381 private function extCommand(int $a_nr): string
382 {
383 $selected = $this->getIncomingFiles();
384
385 if ($selected === []) {
386 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("no_checkbox"), true);
387 $this->ctrl->redirect($this, "listFiles");
388 }
389
390 // check if only one item is select, if command does not allow multiple selection
391 if (count($selected) > 1 && ($this->commands[$a_nr]["single"] ?? false)) {
392 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("cont_select_max_one_item"), true);
393 $this->ctrl->redirect($this, "listFiles");
394 }
395
396 $cur_subdir = $this->sanitizeCurrentDirectory();
397
398 // collect files and
399 $files = [];
400 foreach ($selected as $file) {
401 $file = ilUtil::stripSlashes($file);
402 $file = (empty($cur_subdir))
403 ? $file
404 : $cur_subdir . "/" . $file;
405
406 // check wether selected item is a directory
407 if (is_dir($this->main_absolute_dir . "/" . $file) &&
408 !$this->commands[$a_nr]["allow_dir"]) {
409 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("select_a_file"), true);
410 $this->ctrl->redirect($this, "listFiles");
411 }
412
413 $files[] = $file;
414 }
415
416 if ($this->commands[$a_nr]["single"] ?? false) {
417 $files = array_shift($files);
418 }
419
420 $obj = $this->commands[$a_nr]["object"];
421 $method = $this->commands[$a_nr]["method"];
422
423 return (string) $obj->$method($files);
424 }
425
426 public function setAllowDirectoryCreation(bool $a_val): void
427 {
428 $this->directory_creation = $a_val;
429 }
430
431 public function getAllowDirectoryCreation(): bool
432 {
433 return $this->directory_creation;
434 }
435
439 public function setAllowFileCreation(bool $a_val): void
440 {
441 $this->file_creation = $a_val;
442 }
443
444 public function getAllowFileCreation(): bool
445 {
446 return $this->file_creation;
447 }
448
449 public function listFiles(?ilTable2GUI $a_table_gui = null): void
450 {
451 global $DIC;
452 $ilToolbar = $DIC['ilToolbar'];
453 $lng = $DIC['lng'];
454 $ilCtrl = $DIC['ilCtrl'];
455
456 $dir = $this->parseCurrentDirectory();
457
458 $this->ctrl->setParameter($this, self::PARAMETER_CDIR, $dir["subdir"]);
459
460 // toolbar for adding files/directories
461 $ilToolbar->setFormAction($ilCtrl->getFormAction($this), true);
462
463 if ($this->getAllowDirectories() && $this->getAllowDirectoryCreation()) {
464 $ti = new ilTextInputGUI($this->lng->txt("cont_new_dir"), self::POST_PARAM_NEW_DIR);
465 $ti->setMaxLength(80);
466 $ti->setSize(10);
467 $ilToolbar->addInputItem($ti, true);
468 $ilToolbar->addFormButton($lng->txt("create"), "createDirectory");
469
470 $ilToolbar->addSeparator();
471 }
472 if ($this->getAllowFileCreation()) {
473 $fi = new ilFileInputGUI($this->lng->txt("cont_new_file"), "new_file");
474 $fi->setSize(10);
475 $ilToolbar->addInputItem($fi, true);
476 $ilToolbar->addFormButton($lng->txt("upload"), "uploadFile");
477 }
478 if (ilUploadFiles::_getUploadDirectory() && $this->getAllowFileCreation() && $this->getUseUploadDirectory()) {
479 $ilToolbar->addSeparator();
481 $options[""] = $lng->txt("cont_select_from_upload_dir");
482 foreach ($files as $file) {
483 $file = htmlspecialchars($file, ENT_QUOTES, "utf-8");
484 $options[$file] = $file;
485 }
486 $si = new ilSelectInputGUI($this->lng->txt("cont_uploaded_file"), self::POST_PARAM_UPLOADED_FILE);
487 $si->setOptions($options);
488 $ilToolbar->addInputItem($si, true);
489 $ilToolbar->addFormButton($lng->txt("copy"), "uploadFile");
490 }
491
492 $fs_table = $this->getTable($dir["dir"], $dir["subdir"]);
493
494 if ($this->getTitle() !== "") {
495 $fs_table->setTitle($this->getTitle());
496 }
497 if (
498 $this->wrapper->query()->has(self::PARAM_RESETOFFSET)
499 && $this->wrapper->query()->retrieve(
500 self::PARAM_RESETOFFSET,
501 $this->refinery->kindlyTo()->int()
502 ) == 1) {
503 $fs_table->resetOffset();
504 }
505 $this->tpl->setContent($fs_table->getHTML());
506 }
507
508 public function getTable(string $a_dir, string $a_subdir): \ilFileSystemTableGUI
509 {
510 return new ilFileSystemTableGUI(
511 $this,
512 "listFiles",
513 $a_dir,
514 $a_subdir,
515 $this->label_enable,
516 $this->file_labels,
517 $this->label_header,
518 $this->commands,
519 $this->getPostDirPath(),
520 $this->getTableId()
521 );
522 }
523
524 public function renameFileForm(string $a_file): void
525 {
526 $cur_subdir = $this->sanitizeCurrentDirectory();
527 $file = $this->main_absolute_dir . "/" . $a_file;
528
529 $this->ctrl->setParameter($this, self::PARAM_OLD_NAME, basename($a_file));
530 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
531 $form = new ilPropertyFormGUI();
532
533 // file/dir name
534 $ti = new ilTextInputGUI($this->lng->txt("name"), self::POST_PARAM_NEW_NAME);
535 $ti->setMaxLength(200);
536 $ti->setSize(40);
537 $ti->setValue(basename($a_file));
538 $form->addItem($ti);
539
540 // save and cancel commands
541 $form->addCommandButton("renameFile", $this->lng->txt("rename"));
542 $form->addCommandButton("cancelRename", $this->lng->txt("cancel"));
543 $form->setFormAction($this->ctrl->getFormAction($this, "renameFile"));
544
545 if (is_dir($file)) {
546 $form->setTitle($this->lng->txt("cont_rename_dir"));
547 } else {
548 $form->setTitle($this->lng->txt("rename_file"));
549 }
550
551 $this->tpl->setContent($form->getHTML());
552 }
553
554 public function renameFile(): void
555 {
556 $new_name = $this->wrapper->post()->has(self::POST_PARAM_NEW_NAME)
557 ? $this->wrapper->post()->retrieve(self::POST_PARAM_NEW_NAME, $this->refinery->to()->string())
558 : '';
559
560 $new_name = str_replace("..", "", ilUtil::stripSlashes($new_name));
561 $new_name = str_replace("/", "", $new_name);
562 if ($new_name === "") {
563 throw new LogicException($this->lng->txt("enter_new_name"));
564 }
565
566 $pi = pathinfo($new_name);
567 $suffix = $pi["extension"] ?? "";
568 if ($suffix != "" && !$this->isValidSuffix($suffix)) {
569 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("file_no_valid_file_type") . " ($suffix)", true);
570 $this->ctrl->redirect($this, "listFiles");
571 }
572
573 $cur_subdir = $this->sanitizeCurrentDirectory();
574 $dir = (empty($cur_subdir))
575 ? $this->main_absolute_dir . "/"
576 : $this->main_absolute_dir . "/" . $cur_subdir . "/";
577
578 $old_name = $this->wrapper->query()->has(self::PARAM_OLD_NAME)
579 ? $this->wrapper->query()->retrieve(self::PARAM_OLD_NAME, $this->refinery->to()->string())
580 : null;
581
582 // check if this path is inside $dir
583 $old_name = ilUtil::stripSlashes($old_name);
584 $realpath = realpath($dir . $old_name);
585 if (!str_starts_with($realpath, realpath($dir))) {
586 throw new ilException($this->lng->txt("no_permission"));
587 }
588
589 if (is_dir($dir . $old_name)) {
590 rename($dir . $old_name, $dir . $new_name);
591 } else {
592 try {
593 ilFileUtils::rename($dir . $old_name, $dir . $new_name);
594 } catch (ilException $e) {
595 $this->tpl->setOnScreenMessage('failure', $e->getMessage(), true);
596 $this->ctrl->redirect($this, "listFiles");
597 }
598 }
599
600 ilFileUtils::renameExecutables($this->main_absolute_dir);
601 if (is_dir($dir . $new_name)) {
602 $this->tpl->setOnScreenMessage(
603 'success',
604 $this->lng->txt("cont_dir_renamed"),
605 true
606 );
607 $this->setPerformedCommand("rename_dir", [self::PARAM_OLD_NAME => $old_name,
608 self::POST_PARAM_NEW_NAME => $new_name
609 ]);
610 } else {
611 $this->tpl->setOnScreenMessage(
612 'success',
613 $this->lng->txt("cont_file_renamed"),
614 true
615 );
616 $this->setPerformedCommand("rename_file", [self::PARAM_OLD_NAME => $old_name,
617 self::POST_PARAM_NEW_NAME => $new_name
618 ]);
619 }
620 $this->ctrl->redirect($this, "listFiles");
621 }
622
623 public function cancelRename(): void
624 {
625 $this->ctrl->redirect($this, "listFiles");
626 }
627
628 public function createDirectory(): void
629 {
630 global $DIC;
631 $lng = $DIC['lng'];
632
633 // determine directory
634 $cur_subdir = $this->sanitizeCurrentDirectory();
635 $cur_dir = (empty($cur_subdir))
636 ? $this->main_absolute_dir
637 : $this->main_absolute_dir . "/" . $cur_subdir;
638
639 $new_dir = $this->wrapper->post()->has(self::POST_PARAM_NEW_DIR)
640 ? $this->wrapper->post()->retrieve(self::POST_PARAM_NEW_DIR, $this->refinery->to()->string())
641 : '';
642
643 $new_dir = str_replace(".", "", ilUtil::stripSlashes($new_dir));
644 $new_dir = str_replace("/", "", $new_dir);
645
646 if (!empty($new_dir)) {
647 ilFileUtils::makeDir($cur_dir . "/" . $new_dir);
648 if (is_dir($cur_dir . "/" . $new_dir)) {
649 $this->tpl->setOnScreenMessage('success', $lng->txt("cont_dir_created"), true);
650 $this->setPerformedCommand("create_dir", ["name" => $new_dir]);
651 }
652 } else {
653 $this->tpl->setOnScreenMessage('failure', $lng->txt("cont_enter_a_dir_name"), true);
654 }
655 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
656 $this->ctrl->redirect($this, 'listFiles');
657 }
658
659 public function uploadFile(): void
660 {
661 global $DIC;
662 $lng = $DIC['lng'];
663
664 // determine directory
665 $cur_subdir = $this->sanitizeCurrentDirectory();
666 $cur_dir = (empty($cur_subdir))
667 ? $this->main_absolute_dir
668 : $this->main_absolute_dir . "/" . $cur_subdir;
669
670 $tgt_file = null;
671
672 $pi = pathinfo((string) $_FILES["new_file"]["name"]);
673 $suffix = $pi["extension"] ?? "";
674 if (!$this->isValidSuffix($suffix)) {
675 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("file_no_valid_file_type") . " ($suffix)", true);
676 $this->ctrl->redirect($this, "listFiles");
677 }
678
679 $uploaded_file = $this->wrapper->post()->has(self::POST_PARAM_UPLOADED_FILE)
680 ? $this->wrapper->post()->retrieve(self::POST_PARAM_UPLOADED_FILE, $this->refinery->to()->string())
681 : '';
682 if (is_file($_FILES["new_file"]["tmp_name"])) {
683 $name = $this->secure(ilUtil::stripSlashes($_FILES["new_file"]["name"]));
684 $tgt_file = $cur_dir . "/" . $name;
685
686 // use filesystem directly
687 //ilFileUtils::moveUploadedFile(, $name, $tgt_file);
688 $upload = $DIC->upload();
689
690 // If the upload has not yet been processed make sure he gets processed now.
691 if (!$upload->hasBeenProcessed()) {
692 $upload->process();
693 }
694
695
696 if (!$upload->hasUploads()) {
697 throw new ilException(
698 $DIC->language()->txt("upload_error_file_not_found")
699 );
700 }
701 $upload_result = $upload->getResults()[$_FILES["new_file"]["tmp_name"]];
702 if ($upload_result instanceof UploadResult) {
703 $processing_status = $upload_result->getStatus();
704 if ($processing_status->getCode() === ProcessingStatus::REJECTED) {
705 $this->tpl->setOnScreenMessage(
706 'failure',
707 $processing_status->getMessage(),
708 true
709 );
710 $this->ctrl->redirect($this, "listFiles");
711 }
712 }
713
714 $upload->moveOneFileTo(
715 $upload_result,
716 LegacyPathHelper::createRelativePath($cur_dir . "/"),
717 LegacyPathHelper::deriveLocationFrom($cur_dir),
718 $name,
719 true
720 );
721 // end upload
722 } elseif ($uploaded_file) {
723 // check if the file is in the ftp directory and readable
724 if (ilUploadFiles::_checkUploadFile($uploaded_file)) {
725 $tgt_file = $cur_dir . "/" . ilUtil::stripSlashes($uploaded_file);
726
727 // copy uploaded file to data directory
728 ilUploadFiles::_copyUploadFile($uploaded_file, $tgt_file);
729 }
730 } elseif (trim((string) $_FILES["new_file"]["name"]) === "") {
731 $this->tpl->setOnScreenMessage('failure', $lng->txt("cont_enter_a_file"), true);
732 }
733
734 if ($tgt_file && is_file($tgt_file)) {
735 $unzip = null;
736 if (MimeType::getMimeType($tgt_file) === "application/zip") {
737 $this->ctrl->setParameter($this, self::PARAM_UPFILE, basename($tgt_file));
738 $url = $this->ctrl->getLinkTarget($this, self::CMD_UNZIP_FILE);
739 $this->ctrl->setParameter($this, self::PARAM_UPFILE, "");
740
741 $unzip_link = $this->ui_factory->link()->standard(
742 $this->lng->txt("unzip"),
743 $url
744 );
745
746 $unzip = " " . $this->ui_renderer->render($unzip_link);
747 }
748
749 $this->tpl->setOnScreenMessage('success', $lng->txt("cont_file_created") . $unzip, true);
750
751 $this->setPerformedCommand(
752 "create_file",
753 ["name" => substr($tgt_file, strlen($this->main_absolute_dir) + 1)]
754 );
755 }
756
757 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
758
759 ilFileUtils::renameExecutables($this->main_absolute_dir);
760
761 $this->ctrl->redirect($this, 'listFiles');
762 }
763
764 public function confirmDeleteFile(array $a_files): void
765 {
766 global $DIC;
767 $ilCtrl = $DIC['ilCtrl'];
768 $tpl = $DIC['tpl'];
769 $lng = $DIC['lng'];
770
771 $cgui = new ilConfirmationGUI();
772 $cgui->setFormAction($ilCtrl->getFormAction($this));
773 $cgui->setHeaderText($lng->txt("info_delete_sure"));
774 $cgui->setCancel($lng->txt("cancel"), "listFiles");
775 $cgui->setConfirm($lng->txt("delete"), "deleteFile");
776
777 foreach ($a_files as $i) {
778 $cgui->addItem("file[]", $i, $i);
779 }
780
781 $tpl->setContent($cgui->getHTML());
782 }
783
784 public function deleteFile(): void
785 {
786 if (!$this->wrapper->post()->has(self::POST_PARAM_FILE)) {
787 throw new LogicException($this->lng->txt("no_checkbox"));
788 }
789 $is_dir = false;
790 $post_file = null;
791
792 $postfiles = $this->wrapper->post()->retrieve(
793 self::POST_PARAM_FILE,
794 $this->refinery->to()->listOf(
795 $this->refinery->to()->string()
796 )
797 );
798 foreach ($postfiles as $post_file) {
799 if (ilUtil::stripSlashes($post_file) === "..") {
800 throw new LogicException($this->lng->txt("no_checkbox"));
801 break;
802 }
803
804 $cur_subdir = $this->sanitizeCurrentDirectory();
805 $cur_dir = (empty($cur_subdir))
806 ? $this->main_absolute_dir
807 : $this->main_absolute_dir . "/" . $cur_subdir;
808 $pi = pathinfo((string) $post_file);
809 $file = $cur_dir . "/" . ilUtil::stripSlashes($pi["basename"]);
810
811 if (is_file($file)) {
812 unlink($file);
813 }
814
815 if (is_dir($file)) {
816 $is_dir = true;
817 ilFileUtils::delDir($file);
818 }
819 }
820
821 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
822 if ($is_dir) {
823 $this->tpl->setOnScreenMessage('success', $this->lng->txt("cont_dir_deleted"), true);
824 $this->setPerformedCommand(
825 "delete_dir",
826 ["name" => ilUtil::stripSlashes($post_file)]
827 );
828 } else {
829 $this->tpl->setOnScreenMessage('success', $this->lng->txt("cont_file_deleted"), true);
830 $this->setPerformedCommand(
831 "delete_file",
832 ["name" => ilUtil::stripSlashes($post_file)]
833 );
834 }
835 $this->ctrl->redirect($this, 'listFiles');
836 }
837
838 public function unzipFile(?string $a_file = null): void
839 {
840 // #17470 - direct unzip call (after upload)
841 $upname = $this->wrapper->query()->has(self::PARAM_UPFILE)
842 ? $this->wrapper->query()->retrieve(self::PARAM_UPFILE, $this->refinery->to()->string())
843 : null;
844 if (is_null($a_file) && $upname !== null) {
845 $a_file = basename((string) $upname);
846 }
847
848 $cur_subdir = $this->sanitizeCurrentDirectory();
849 $cur_dir = (empty($cur_subdir))
850 ? $this->main_absolute_dir
851 : $this->main_absolute_dir . "/" . $cur_subdir;
852 $a_file = $this->main_absolute_dir . "/" . $a_file;
853
854 if (is_file($a_file)) {
855 $cur_files = array_keys(ilFileUtils::getDir($cur_dir));
856 $cur_files_r = iterator_to_array(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($cur_dir)));
857
858 $this->unzip->unzip(
859 $a_file,
860 null,
861 true,
862 !$this->getAllowDirectories(),
863 false
864 );
865
866 $new_files = array_keys(ilFileUtils::getDir($cur_dir));
867 $new_files_r = iterator_to_array(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($cur_dir)));
868
869 $diff = array_diff($new_files, $cur_files);
870 $diff_r = array_diff($new_files_r, $cur_files_r);
871
872 // unlink forbidden file types
873 foreach (array_keys($diff_r) as $f) {
874 $pi = pathinfo($f);
875 if (!is_dir($f) && !$this->isValidSuffix(strtolower($pi["extension"] ?? ''))) {
876 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("file_some_invalid_file_types_removed") . " (" . $pi["extension"] . ")", true);
877 unlink($f);
878 }
879 }
880
881 if ($diff !== []) {
882 if ($this->getAllowDirectories()) {
883 $new_files = [];
884
885 foreach ($diff as $new_item) {
886 if (is_dir($cur_dir . "/" . $new_item)) {
887 ilFileUtils::recursive_dirscan($cur_dir . "/" . $new_item, $new_files);
888 }
889 }
890
891 if (isset($new_files["path"])) {
892 foreach ($new_files["path"] as $idx => $path) {
893 $path = substr((string) $path, strlen($this->main_absolute_dir) + 1);
894 $diff[] = $path . $new_files[self::POST_PARAM_FILE][$idx];
895 }
896 }
897 }
898
899 $this->setPerformedCommand(
900 "unzip_file",
901 ["added" => $diff
902 ]
903 );
904 }
905 }
906
907 ilFileUtils::renameExecutables($this->main_absolute_dir);
908
909 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
910 $this->tpl->setOnScreenMessage('success', $this->lng->txt("cont_file_unzipped"), true);
911 $this->ctrl->redirect($this, "listFiles");
912 }
913
914 public function downloadFile(string $a_file): void
915 {
916 $file = $this->main_absolute_dir . "/" . $a_file;
917
918 if (is_file($file) && !(is_dir($file))) {
919 ilFileDelivery::deliverFileLegacy($file, basename($a_file));
920 exit;
921 }
922 $this->ctrl->saveParameter($this, self::PARAMETER_CDIR);
923 $this->ctrl->redirect($this, "listFiles");
924 }
925
929 public function getActionCommands(): array
930 {
931 return $this->commands;
932 }
933
934 public function defineCommands(): void
935 {
936 $this->commands = [
937 0 => [
938 "object" => $this,
939 "method" => "downloadFile",
940 "name" => $this->lng->txt("download"),
941 "int" => true,
942 "single" => true
943 ],
944 1 => [
945 "object" => $this,
946 "method" => "confirmDeleteFile",
947 "name" => $this->lng->txt("delete"),
948 "allow_dir" => true,
949 "int" => true
950 ],
951 2 => [
952 "object" => $this,
953 "method" => self::CMD_UNZIP_FILE,
954 "name" => $this->lng->txt("unzip"),
955 "allow_dir" => true,
956 "int" => true,
957 "single" => true
958 ],
959 3 => [
960 "object" => $this,
961 "method" => "renameFileForm",
962 "name" => $this->lng->txt("rename"),
963 "allow_dir" => true,
964 "int" => true,
965 "single" => true
966 ],
967 ];
968 }
969
970 private function sanitizeCurrentDirectory(): string
971 {
972 $cur_subdir = $this->wrapper->query()->has(self::PARAMETER_CDIR)
973 ? $this->wrapper->query()->retrieve(self::PARAMETER_CDIR, $this->refinery->to()->string())
974 : '';
975
976 return str_replace(
977 "..",
978 "",
979 ilUtil::stripSlashes($cur_subdir)
980 );
981 }
982}
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:31
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:68