ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilObjFile.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
8 
9 require_once("Services/Object/classes/class.ilObject2.php");
10 require_once('Modules/File/classes/class.ilFSStorageFile.php');
11 
21 class ilObjFile extends ilObject2
22 {
23  const MODE_FILELIST = "filelist";
24  const MODE_OBJECT = "object";
32  protected $filename = '';
36  protected $filetype = '';
40  protected $filemaxsize = "20000000"; // not used yet
44  protected $filesize;
52  public $mode = self::MODE_OBJECT;
56  protected $page_count = 0;
60  protected $rating = false;
64  private $file_storage = null;
68  protected $log = null;
72  protected $version = 1;
76  protected $max_version = 1;
80  protected $action = null;
84  protected $rollback_version = null;
88  protected $rollback_user_id = null;
89 
90 
97  public function __construct($a_id = 0, $a_call_by_reference = true)
98  {
99  $this->version = 0;
100  $this->max_version = 0;
101  $this->raise_upload_error = true;
102 
103  $this->log = ilLoggerFactory::getLogger('file');
104 
105  parent::__construct($a_id, $a_call_by_reference);
106 
107  if ($this->getId()) {
108  $this->initFileStorage();
109  }
110  }
111 
112 
113  public function initType()
114  {
115  $this->type = "file";
116  }
117 
118 
124  protected function doCreate($a_upload = false)
125  {
126  $this->createProperties($a_upload);
127  }
128 
129 
137  public function createProperties($a_upload = false)
138  {
139  global $DIC;
140 
141  // Create file directory
142  $this->initFileStorage();
143  $this->file_storage->create();
144 
145  if ($a_upload) {
146  return true;
147  }
148 
149  // not upload mode
150  ilHistory::_createEntry($this->getId(), "create", $this->getFileName() . ",1" . ",1");
151  $this->addNewsNotification("file_created");
152 
153  // New Item
154  $default_visibility = ilNewsItem::_getDefaultVisibilityForRefId($_GET['ref_id']);
155  if ($default_visibility == "public") {
156  ilBlockSetting::_write("news", "public_notifications", 1, 0, $this->getId());
157  }
158 
159  // log creation
160  $this->log->debug("ilObjFile::createProperties, ID: " . $this->getId() . ", Name: "
161  . $this->getFileName() . ", Type: " . $this->getFileType() . ", Size: "
162  . $this->getFileSize() . ", Mode: " . $this->getMode() . ", Name(Bytes): "
163  . implode(":", ilStr::getBytesForString($this->getFileName())));
164  $this->log->logStack(ilLogLevel::DEBUG);
165 
166  $DIC->database()->insert('file_data', $this->getArrayForDatabase());
167 
168  //add metadata to database
169  $metadata = [
170  'meta_lifecycle_id' => ['integer', $DIC->database()->nextId('il_meta_lifecycle')],
171  'rbac_id' => ['integer', $this->getId()],
172  'obj_id' => ['integer', $this->getId()],
173  'obj_type' => ['text', "file"],
174  'meta_version' => ['integer', (int) $this->getVersion()],
175  ];
176  $DIC->database()->insert('il_meta_lifecycle', $metadata);
177 
178  // no meta data handling for file list files
179  if ($this->getMode() != self::MODE_FILELIST) {
180  $this->createMetaData();
181  }
182  }
183 
184 
188  public function setNoMetaDataCreation($a_status)
189  {
190  $this->no_meta_data_creation = (bool) $a_status;
191  }
192 
193 
194  protected function beforeCreateMetaData()
195  {
196  return !(bool) $this->no_meta_data_creation;
197  }
198 
199 
200  protected function beforeUpdateMetaData()
201  {
202  return !(bool) $this->no_meta_data_creation;
203  }
204 
205 
209  protected function doCreateMetaData()
210  {
211  // add technical section with file size and format
212  $md_obj = new ilMD($this->getId(), 0, $this->getType());
213  $technical = $md_obj->addTechnical();
214  $technical->setSize($this->getFileSize());
215  $technical->save();
216  $format = $technical->addFormat();
217  $format->setFormat($this->getFileType());
218  $format->save();
219  $technical->update();
220  }
221 
222 
223  protected function beforeMDUpdateListener($a_element)
224  {
225  // Check file extension
226  // Removing the file extension is not allowed
227  include_once 'Services/MetaData/classes/class.ilMD.php';
228  $md = new ilMD($this->getId(), 0, $this->getType());
229  if (!is_object($md_gen = $md->getGeneral())) {
230  return false;
231  }
232  $title = $this->checkFileExtension($this->getFileName(), $md_gen->getTitle());
233  $md_gen->setTitle($title);
234  $md_gen->update();
235 
236  return true;
237  }
238 
239 
240  protected function doMDUpdateListener($a_element)
241  {
242  // handling for technical section
243  include_once 'Services/MetaData/classes/class.ilMD.php';
244 
245  switch ($a_element) {
246  case 'Technical':
247 
248  // Update Format (size is not stored in db)
249  $md = new ilMD($this->getId(), 0, $this->getType());
250  if (!is_object($md_technical = $md->getTechnical())) {
251  return false;
252  }
253 
254  foreach ($md_technical->getFormatIds() as $id) {
255  $md_format = $md_technical->getFormat($id);
256  ilObjFile::_writeFileType($this->getId(), $md_format->getFormat());
257  $this->setFileType($md_format->getFormat());
258  break;
259  }
260 
261  break;
262  }
263 
264  return true;
265  }
266 
267 
273  public function getDirectory($a_version = 0)
274  {
275  $version_subdir = "";
276 
277  if ($a_version) {
278  // BEGIN WebDAV Avoid double slash before version subdirectory
279  $version_subdir = sprintf("%03d", $a_version);
280  // END WebDAV Avoid double slash before version subdirectory
281  }
282 
283  if (!is_object($this->file_storage)) {
284  $this->initFileStorage();
285  }
286 
287  $str = $this->file_storage->getAbsolutePath() . '/' . $version_subdir;
288 
289  return $str;
290  }
291 
292 
293  public function createDirectory()
294  {
296  }
297 
298 
299  public function raiseUploadError($a_raise = true)
300  {
301  $this->raise_upload_error = $a_raise;
302  }
303 
304 
314  public function getUploadFile($a_upload_file, $a_filename, $a_prevent_preview = false)
315  {
316  global $DIC;
317 
318  $upload = $DIC->upload();
319  $result = null;
320 
321  if ($upload->hasUploads()) {
322  if (!$upload->hasBeenProcessed()) {
323  $upload->process();
324  }
328  $result = $upload->getResults()[$a_upload_file];
329  if ($result->getStatus()->getCode() === \ILIAS\FileUpload\DTO\ProcessingStatus::OK) {
330  $metadata = $result->getMetaData();
333  $this->doUpdate();
334  }
335  $a_name = $result->getName();
336  $this->setFileName($a_name);
337 
338  // bugfix mantis 26236:
339  // ensure that version and max_version are correct to prevent the upload file from being versioned incorrectly
340  if ($this->getVersion() > 0) {
341  $file_hist_entries = (array) ilHistory::_getEntriesForObject($this->getId(), $this->getType());
342  $highest_version = 0;
343  foreach ($file_hist_entries as $file_hist_entry) {
344  $version = $this->parseInfoParams($file_hist_entry)['version'];
345  if ($version > $highest_version) {
346  $highest_version = $version;
347  }
348  }
349  if ($this->getVersion() < $highest_version) {
350  $this->setVersion($highest_version);
351  }
352  if ($this->getVersion() > $this->getMaxVersion()) {
353  $this->setMaxVersion($this->getVersion());
354  }
355  }
356 
357  $this->setVersion($this->getMaxVersion() + 1);
358  $this->setMaxVersion($this->getMaxVersion() + 1);
359 
360  if (!is_dir($this->getDirectory($this->getVersion()))) {
362  }
363 
364  $target_directory = $this->getDirectory($this->getVersion()) . "/";
365  $relative_path_to_file = LegacyPathHelper::createRelativePath($target_directory);
366 
367  $upload->moveOneFileTo($result, $relative_path_to_file, Location::STORAGE);
368 
369  $this->handleQuotaUpdate($this);
370 
371  // create preview?
372  if (!$a_prevent_preview) {
373  $this->createPreview(false);
374  }
375  } else {
376  throw new ilFileException('not supported File');
377  }
378  }
379 
380  return $result;
381  }
382 
383 
392  public function replaceFile($a_upload_file, $a_filename)
393  {
394  if ($result = $this->getUploadFile($a_upload_file, $a_filename, true)) {
395  ilHistory::_createEntry($this->getId(), "replace", $a_filename . "," . $this->getVersion() . "," . $this->getMaxVersion());
396  $this->addNewsNotification("file_updated");
397 
398  // create preview
399  $this->createPreview(true);
400  }
401 
402  return $result;
403  }
404 
405 
414  public function addFileVersion($a_upload_file, $a_filename)
415  {
416  if ($result = $this->getUploadFile($a_upload_file, $a_filename, true)) {
417  ilHistory::_createEntry($this->getId(), "new_version", $result->getName() . "," . $this->getVersion() . "," . $this->getMaxVersion());
418  $this->addNewsNotification("file_updated");
419 
420  // create preview
421  $this->createPreview($this->getVersion() > 1);
422  }
423 
424  return $result;
425  }
426 
427 
431  public function copy($a_source, $a_destination)
432  {
433  return copy($a_source, $this->getDirectory() . "/" . $a_destination);
434  }
435 
436 
440  public function clearDataDirectory()
441  {
442  ilUtil::delDir($this->getDirectory());
443  $this->createDirectory();
444  }
445 
446 
452  public function deleteVersions($a_hist_entry_ids = null)
453  {
454  if ($a_hist_entry_ids == null || count($a_hist_entry_ids) < 1) {
455  $this->clearDataDirectory();
456 
458 
459  self::handleQuotaUpdate($this);
460  } else {
461  $actualVersionDeleted = false;
462 
463  // get all versions
464  $versions = $this->getVersions();
465 
466  // delete each version
467  foreach ($a_hist_entry_ids as $hist_id) {
468  $entry = null;
469 
470  // get version
471  foreach ($versions as $index => $version) {
472  if ($version["hist_entry_id"] == $hist_id) {
473  // remove each history entry
475 
476  // delete directory
477  $version_dir = $this->getDirectory($version["version"]);
478  ilUtil::delDir($version_dir);
479 
480  // is actual version?
481  if ($version["version"] == $this->getVersion()) {
482  $actualVersionDeleted = true;
483  }
484 
485  // remove from array
486  unset($versions[$index]);
487  break;
488  }
489  }
490  }
491 
492  // update actual version if it was deleted before
493  if ($actualVersionDeleted) {
494  // get newest version (already sorted by getVersions)
495  $version = reset($versions);
496  $version['max_version'] = $this->getMaxVersion();
497  $this->updateWithVersion($version);
498  } else {
499  // updateWithVersion() will trigger quota, too
500  self::handleQuotaUpdate($this);
501  }
502  }
503  }
504 
505 
506  protected function doRead()
507  {
508  global $DIC;
509 
510  $q = "SELECT * FROM file_data WHERE file_id = %s";
511  $r = $DIC->database()->queryF($q, ['integer'], [$this->getId()]);
512  $row = $r->fetchObject();
513 
514  $this->setFileName($row->file_name);
515  $this->setFileType($row->file_type);
516  $this->setFileSize($row->file_size);
517  $this->setVersion($row->version ? $row->version : 1);
518  $this->setMaxVersion($row->max_version ? $row->max_version : 1);
519  $this->setMode($row->f_mode);
520  $this->setRating($row->rating);
521  $this->setPageCount($row->page_count);
522 
523  $this->initFileStorage();
524  }
525 
526 
527  protected function beforeUpdate()
528  {
529  // no meta data handling for file list files
530  if ($this->getMode() != self::MODE_FILELIST) {
531  $this->updateMetaData();
532  }
533 
534  return true;
535  }
536 
537 
538  protected function doUpdate()
539  {
540  global $DIC;
541 
542  $a_columns = $this->getArrayForDatabase();
543  $DIC->database()->update('file_data', $a_columns, [
544  'file_id' => [
545  'integer',
546  $this->getId(),
547  ],
548  ]);
549 
550  // update metadata with the current file version
551  $meta_version_column = ['meta_version' => ['integer', (int) $this->getVersion()]];
552  $DIC->database()->update('il_meta_lifecycle', $meta_version_column, [
553  'obj_id' => [
554  'integer',
555  $this->getId(),
556  ],
557  ]);
558 
559  self::handleQuotaUpdate($this);
560 
561  return true;
562  }
563 
564 
568  protected function doUpdateMetaData()
569  {
570  // add technical section with file size and format
571  $md_obj = new ilMD($this->getId(), 0, $this->getType());
572  if (!is_object($technical = $md_obj->getTechnical())) {
573  $technical = $md_obj->addTechnical();
574  $technical->save();
575  }
576  $technical->setSize($this->getFileSize());
577 
578  $format_ids = $technical->getFormatIds();
579  if (count($format_ids) > 0) {
580  $format = $technical->getFormat($format_ids[0]);
581  $format->setFormat($this->getFileType());
582  $format->update();
583  } else {
584  $format = $technical->addFormat();
585  $format->setFormat($this->getFileType());
586  $format->save();
587  }
588  $technical->update();
589  }
590 
591 
595  public function setFileName($a_name)
596  {
597  $this->filename = $a_name;
598  }
599 
600 
604  public function getFileName()
605  {
606  return $this->filename;
607  }
608 
609 
613  public function setFileType($a_type)
614  {
615  $this->filetype = $a_type;
616  }
617 
618 
622  public function getFileType()
623  {
624  return $this->filetype;
625  }
626 
627 
631  public function setFileSize($a_size)
632  {
633  $this->filesize = $a_size;
634  }
635 
636 
637  public function getFileSize()
638  {
639  return $this->filesize;
640  }
641 
642 
643  public function setAction($a_action)
644  {
645  $this->action = $a_action;
646  }
647 
648 
649  public function getAction()
650  {
651  return $this->action;
652  }
653 
654 
655  public function setRollbackVersion($a_rollback_version)
656  {
657  $this->rollback_version = $a_rollback_version;
658  }
659 
660 
661  public function getRollbackVersion()
662  {
664  }
665 
666 
667  public function setRollbackUserId($a_rollback_user_id)
668  {
669  $this->rollback_user_id = $a_rollback_user_id;
670  }
671 
672 
673  public function getRollbackUserId()
674  {
676  }
677 
678 
685  public function getDiskUsage()
686  {
687  require_once("./Modules/File/classes/class.ilObjFileAccess.php");
688 
689  return ilObjFileAccess::_lookupDiskUsage($this->id);
690  }
691 
692 
693  // END PATCH WebDAV Encapsulate file access in ilObjFile class.
694  public function getFile($a_hist_entry_id = null)
695  {
696  if (is_null($a_hist_entry_id)) {
697  $file = $this->getDirectory($this->getVersion()) . "/" . $this->getFileName();
698  } else {
699  require_once("./Services/History/classes/class.ilHistory.php");
700  $entry = ilHistory::_getEntryByHistoryID($a_hist_entry_id);
701 
702  if ($entry === false) {
703  return false;
704  }
705 
706  $data = $this->parseInfoParams($entry);
707  $file = $this->getDirectory($data["version"]) . "/" . $data["filename"];
708  }
709 
710  return $file;
711  }
712 
713 
714  // END PATCH WebDAV Encapsulate file access in ilObjFile class.
715 
716  public function setVersion($a_version)
717  {
718  $this->version = $a_version;
719  }
720 
721 
722  public function getVersion()
723  {
724  return $this->version;
725  }
726 
727 
728  public function setMaxVersion($a_max_version)
729  {
730  $this->max_version = $a_max_version;
731  }
732 
733 
734  public function getMaxVersion()
735  {
736  return $this->max_version;
737  }
738 
739 
745  public function setMode($a_mode)
746  {
747  $this->mode = $a_mode;
748  }
749 
750 
756  public function getMode()
757  {
758  return $this->mode;
759  }
760 
761 
762  public static function _writeFileType($a_id, $a_format)
763  {
764  global $DIC;
765  $ilDB = $DIC['ilDB'];
766 
767  $q = "UPDATE file_data SET " . " file_type = " . $ilDB->quote($a_format, 'text')
768  . " WHERE file_id = " . $ilDB->quote($a_id, 'integer');
769  $res = $ilDB->manipulate($q);
770  }
771 
772 
779  public static function _lookupFileName($a_id)
780  {
781  global $DIC;
782  $ilDB = $DIC['ilDB'];
783 
784  $q = "SELECT * FROM file_data WHERE file_id = " . $ilDB->quote($a_id, 'integer');
785  $r = $ilDB->query($q);
787 
788  $strip_slashes = ilUtil::stripSlashes($row->file_name);
789 
790  return $strip_slashes;
791  }
792 
793 
795  public static function _lookupFileSize($a_id)
796  {
797  require_once("./Modules/File/classes/class.ilObjFileAccess.php");
798 
799  return ilObjFileAccess::_lookupFileSize($a_id);
800  }
801 
802 
806  public static function _lookupVersion($a_id)
807  {
808  require_once("./Modules/File/classes/class.ilObjFileAccess.php");
809 
810  return ilObjFileAccess::_lookupVersion($a_id);
811  }
812 
813 
817  public function determineFileSize($a_hist_entry_id = null)
818  {
819  if (is_null($a_hist_entry_id)) {
820  $file = $this->getDirectory($this->getVersion()) . "/" . $this->getFileName();
821  } else {
822  require_once("./Services/History/classes/class.ilHistory.php");
823  $entry = ilHistory::_getEntryByHistoryID($a_hist_entry_id);
824 
825  if ($entry === false) {
826  return false;
827  }
828 
829  $data = $this->parseInfoParams($entry);
830  $file = $this->getDirectory($data["version"]) . "/" . $data["filename"];
831  }
832  if (is_file($file)) {
833  $this->setFileSize(filesize($file));
834  }
835  }
836 
837 
843  public function sendFile($a_hist_entry_id = null)
844  {
845  $s = new FilePathSanitizer($this);
846  $s->sanitizeIfNeeded();
847 
848  if (is_null($a_hist_entry_id)) {
849  $file = $this->getDirectory($this->getVersion()) . "/" . $this->getFileName();
850  $file = ilFileUtils::getValidFilename($file);
851  } else {
852  $entry = ilHistory::_getEntryByHistoryID($a_hist_entry_id);
853  $data = $this->parseInfoParams($entry);
854  $file = $this->getDirectory($data["version"]) . "/" . $data["filename"];
855  }
856 
857 
858  if ($this->file_storage->fileExists($file)) {
859  global $DIC;
860  $ilClientIniFile = $DIC['ilClientIniFile'];
865  $ilFileDelivery = new ilFileDelivery($file);
866  $ilFileDelivery->setDisposition($this->isInline() ? ilFileDelivery::DISP_INLINE : ilFileDelivery::DISP_ATTACHMENT);
867  $ilFileDelivery->setMimeType($this->guessFileType($file));
868  $ilFileDelivery->setConvertFileNameToAsci((bool) !$ilClientIniFile->readVariable('file_access', 'disable_ascii'));
869 
870  // also returning the 'real' filename if a history file is delivered
871  if ($ilClientIniFile->readVariable('file_access', 'download_with_uploaded_filename')
872  != '1'
873  && is_null($a_hist_entry_id)
874  ) {
875  $ilFileDelivery->setDownloadFileName(ilFileUtils::getValidFilename($this->getTitle()));
876  } else {
877  // $download_file_name = basename($file);
878  /* FSX Info: basename has a Bug with Japanese and other characters, see:
879  * http://stackoverflow.com/questions/32115609/basename-fail-when-file-name-start-by-an-accent
880  * Therefore we can no longer use basename();
881  */
882  $parts = explode(DIRECTORY_SEPARATOR, $file);
883  $download_file_name = end($parts);
884  $download_file_name = ilFileUtils::getValidFilename($download_file_name);
885  $ilFileDelivery->setDownloadFileName($download_file_name);
886  }
887  $ilFileDelivery->deliver();
888 
889  return true;
890  }
891 
892  throw new FileNotFoundException($this->lng->txt('file_not_found_sec'));
893  }
894 
895 
900  public function getFileExtension()
901  {
902  require_once 'Modules/File/classes/class.ilObjFileAccess.php';
903 
905  }
906 
907 
913  public function isInline()
914  {
915  require_once 'Modules/File/classes/class.ilObjFileAccess.php';
916 
917  return ilObjFileAccess::_isFileInline($this->getTitle());
918  }
919 
920 
924  public function isHidden()
925  {
926  require_once 'Modules/File/classes/class.ilObjFileAccess.php';
927 
928  return ilObjFileAccess::_isFileHidden($this->getTitle());
929  }
930  // END WebDAV: Get file extension, determine if file is inline, guess file type.
931 
932 
939  public function guessFileType($a_file = "")
940  {
941  $path = pathinfo($a_file);
942  if ($path["extension"] != "") {
943  $filename = $path["basename"];
944  } else {
945  $filename = "dummy." . $this->getFileExtension();
946  }
947  include_once("./Services/Utilities/classes/class.ilMimeTypeUtil.php");
948  $mime = ilMimeTypeUtil::getMimeType($a_file, $filename, $this->getFileType());
949 
950  return $mime;
951  }
952 
953 
964  protected function doCloneObject($a_new_obj, $a_target_id, $a_copy_id = 0)
965  {
966  global $DIC;
967  $ilDB = $DIC['ilDB'];
968 
969  $a_new_obj->createDirectory();
970  $this->cloneMetaData($a_new_obj);
971 
972  // Copy all file versions
973  ilUtil::rCopy($this->getDirectory(), $a_new_obj->getDirectory());
974 
975  // object created now copy other settings
976  // bugfix mantis 26131
977  $DIC->database()->insert('file_data', $this->getArrayForDatabase($a_new_obj->getId()));
978 
979  // copy all previews
980  require_once("./Services/Preview/classes/class.ilPreview.php");
981  ilPreview::copyPreviews($this->getId(), $a_new_obj->getId());
982 
983  // copy history entries
984  require_once("./Services/History/classes/class.ilHistory.php");
985  ilHistory::_copyEntriesForObject($this->getId(), $a_new_obj->getId());
986 
987  // Copy learning progress settings
988  include_once('Services/Tracking/classes/class.ilLPObjSettings.php');
989  $obj_settings = new ilLPObjSettings($this->getId());
990  $obj_settings->cloneSettings($a_new_obj->getId());
991  unset($obj_settings);
992 
993  // add news notification
994  $a_new_obj->addNewsNotification("file_created");
995 
996  return $a_new_obj;
997  }
998 
999 
1000  protected function beforeDelete()
1001  {
1002  global $DIC;
1003  $ilDB = $DIC['ilDB'];
1004 
1005  // check, if file is used somewhere
1006  $usages = $this->getUsages();
1007  if (count($usages) == 0) {
1008  return true;
1009  }
1010 
1011  return false;
1012  }
1013 
1014 
1015  protected function doDelete()
1016  {
1017  global $DIC;
1018  $ilDB = $DIC['ilDB'];
1019 
1020  // delete file data entry
1021  $q = "DELETE FROM file_data WHERE file_id = " . $ilDB->quote($this->getId(), 'integer');
1022  $this->ilias->db->query($q);
1023 
1024  // delete history entries
1025  require_once("./Services/History/classes/class.ilHistory.php");
1027 
1028  self::handleQuotaUpdate($this);
1029 
1030  // delete entire directory and its content
1031  if (@is_dir($this->getDirectory())) {
1032  ilUtil::delDir($this->getDirectory());
1033  }
1034 
1035  // delete meta data
1036  if ($this->getMode() != self::MODE_FILELIST) {
1037  $this->deleteMetaData();
1038  }
1039 
1040  // delete preview
1041  $this->deletePreview();
1042  }
1043 
1044 
1052  public function export($a_target_dir)
1053  {
1054  $subdir = "il_" . IL_INST_ID . "_file_" . $this->getId();
1055  ilUtil::makeDir($a_target_dir . "/objects/" . $subdir);
1056 
1057  $filedir = $this->getDirectory($this->getVersion());
1058 
1059  if (@!is_dir($filedir)) {
1060  $filedir = $this->getDirectory();
1061  }
1062 
1063  ilUtil::rCopy($filedir, $a_target_dir . "/objects/" . $subdir);
1064  }
1065 
1066 
1070  public static function _deleteAllUsages($a_type, $a_id, $a_usage_hist_nr = 0, $a_usage_lang = "-")
1071  {
1072  global $DIC;
1073  $ilDB = $DIC['ilDB'];
1074 
1075  $and_hist = ($a_usage_hist_nr !== false) ? " AND usage_hist_nr = "
1076  . $ilDB->quote($a_usage_hist_nr, "integer") : "";
1077 
1078  $file_ids = array();
1079  $set = $ilDB->query("SELECT id FROM file_usage" . " WHERE usage_type = "
1080  . $ilDB->quote($a_type, "text") . " AND usage_id= "
1081  . $ilDB->quote($a_id, "integer") . " AND usage_lang= "
1082  . $ilDB->quote($a_usage_lang, "text") . $and_hist);
1083  while ($row = $ilDB->fetchAssoc($set)) {
1084  $file_ids[] = $row["id"];
1085  }
1086 
1087  $ilDB->manipulate("DELETE FROM file_usage WHERE usage_type = "
1088  . $ilDB->quote($a_type, "text") . " AND usage_id = "
1089  . $ilDB->quote((int) $a_id, "integer") . " AND usage_lang= "
1090  . $ilDB->quote($a_usage_lang, "text") . " AND usage_hist_nr = "
1091  . $ilDB->quote((int) $a_usage_hist_nr, "integer"));
1092 
1093  foreach ($file_ids as $file_id) {
1094  self::handleQuotaUpdate(new self($file_id, false));
1095  }
1096  }
1097 
1098 
1102  public static function _saveUsage($a_file_id, $a_type, $a_id, $a_usage_hist_nr = 0, $a_usage_lang = "-")
1103  {
1104  global $DIC;
1105  $ilDB = $DIC['ilDB'];
1106 
1107  // check if file really exists
1108  if (ilObject::_lookupType($a_file_id) != "file") {
1109  return;
1110  }
1111  // #15143
1112  $ilDB->replace("file_usage", array(
1113  "id" => array("integer", (int) $a_file_id),
1114  "usage_type" => array("text", (string) $a_type),
1115  "usage_id" => array("integer", (int) $a_id),
1116  "usage_hist_nr" => array("integer", (int) $a_usage_hist_nr),
1117  "usage_lang" => array("text", $a_usage_lang),
1118  ), array());
1119 
1120  self::handleQuotaUpdate(new self($a_file_id, false));
1121  }
1122 
1123 
1127  public function getUsages()
1128  {
1129  global $DIC;
1130  $ilDB = $DIC['ilDB'];
1131 
1132  // get usages in learning modules
1133  $q = "SELECT * FROM file_usage WHERE id = " . $ilDB->quote($this->getId(), "integer");
1134  $us_set = $ilDB->query($q);
1135  $ret = array();
1136  while ($us_rec = $ilDB->fetchAssoc($us_set)) {
1137  $ret[] = array(
1138  "type" => $us_rec["usage_type"],
1139  "id" => $us_rec["usage_id"],
1140  "lang" => $us_rec["usage_lang"],
1141  "hist_nr" => $us_rec["usage_hist_nr"],
1142  );
1143  }
1144 
1145  return $ret;
1146  }
1147 
1148 
1157  public static function _getFilesOfObject($a_type, $a_id, $a_usage_hist_nr = 0, $a_usage_lang = "-")
1158  {
1159  global $DIC;
1160  $ilDB = $DIC['ilDB'];
1161 
1162  $lstr = "";
1163  if ($a_usage_lang != "") {
1164  $lstr = "usage_lang = " . $ilDB->quote((string) $a_usage_lang, "text") . " AND ";
1165  }
1166 
1167  // get usages in learning modules
1168  $q = "SELECT * FROM file_usage WHERE " . "usage_id = " . $ilDB->quote((int) $a_id, "integer")
1169  . " AND " . "usage_type = " . $ilDB->quote((string) $a_type, "text") . " AND " . $lstr
1170  . "usage_hist_nr = " . $ilDB->quote((int) $a_usage_hist_nr, "integer");
1171  $file_set = $ilDB->query($q);
1172  $ret = array();
1173  while ($file_rec = $ilDB->fetchAssoc($file_set)) {
1174  $ret[$file_rec["id"]] = $file_rec["id"];
1175  }
1176 
1177  return $ret;
1178  }
1179 
1180 
1181  // TODO: What is this function good for??
1182  public function getXMLZip()
1183  {
1184  global $DIC;
1185  $ilias = $DIC['ilias'];
1186 
1187  $zip = PATH_TO_ZIP;
1188 
1189  exec($zip . ' ' . ilUtil::escapeShellArg($this->getDirectory() . '/' . $this->getFileName())
1190  . " " . ilUtil::escapeShellArg($this->getDirectory() . '/' . '1.zip'));
1191 
1192  return $this->getDirectory() . '/1.zip';
1193  }
1194 
1195 
1196  public function addNewsNotification($a_lang_var)
1197  {
1198  // BEGIN WebDAV Suppress news notification for hidden files
1199  if ($this->isHidden()) {
1200  return;
1201  }
1202  // END WebDAV Suppress news notification for hidden files
1203 
1204  global $DIC;
1205  $ilUser = $DIC['ilUser'];
1206 
1207  // Add Notification to news
1208  include_once("./Services/News/classes/class.ilNewsItem.php");
1209  include_once("./Modules/File/classes/class.ilObjFileAccess.php");
1210  $news_item = new ilNewsItem();
1211  $news_item->setContext($this->getId(), $this->getType());
1212  $news_item->setPriority(NEWS_NOTICE);
1213  $news_item->setTitle($a_lang_var);
1214  $news_item->setContentIsLangVar(true);
1215  if ($this->getDescription() != "") {
1216  $news_item->setContent("<p>" . $this->getDescription() . "</p>");
1217  }
1218  $news_item->setUserId($ilUser->getId());
1219  $news_item->setVisibility(NEWS_USERS);
1220  $news_item->create();
1221  }
1222 
1223 
1230  public function initFileStorage()
1231  {
1232  $this->file_storage = new ilFSStorageFile($this->getId());
1233 
1234  return true;
1235  }
1236 
1237 
1247  public function storeUnzipedFile($a_upload_file, $a_filename)
1248  {
1249  $this->setVersion($this->getVersion() + 1);
1250 
1251  if (@!is_dir($this->getDirectory($this->getVersion()))) {
1252  ilUtil::makeDir($this->getDirectory($this->getVersion()));
1253  }
1254 
1255  $file = $this->getDirectory($this->getVersion()) . "/" . $a_filename;
1256 
1257  $file = ilFileUtils::getValidFilename($file);
1258 
1259  ilFileUtils::rename($a_upload_file, $file);
1260 
1261  // create preview
1262  $this->createPreview();
1263  }
1264 
1265 
1273  public static function _lookupAbsolutePath($obj_id, $a_version = null)
1274  {
1275  $file_object = new self($obj_id, false);
1276  $s = new FilePathSanitizer($file_object);
1277  $s->sanitizeIfNeeded();
1278 
1279  return $file_object->getFile($a_version);
1280  }
1281 
1282 
1288  public function checkFileExtension($new_filename, $new_title)
1289  {
1290  include_once './Modules/File/classes/class.ilObjFileAccess.php';
1291  $fileExtension = ilObjFileAccess::_getFileExtension($new_filename);
1292  $titleExtension = ilObjFileAccess::_getFileExtension($new_title);
1293  if ($titleExtension != $fileExtension && strlen($fileExtension) > 0) {
1294  // remove old extension
1295  $pi = pathinfo($this->getFileName());
1296  $suffix = $pi["extension"];
1297  if ($suffix != "") {
1298  if (substr($new_title, strlen($new_title) - strlen($suffix) - 1) == "." . $suffix) {
1299  $new_title = substr($new_title, 0, strlen($new_title) - strlen($suffix) - 1);
1300  }
1301  }
1302  $new_title .= '.' . $fileExtension;
1303  }
1304 
1305  return $new_title;
1306  }
1307 
1308 
1329  public function getVersions($version_ids = null) : array
1330  {
1331  $versions = (array) ilHistory::_getEntriesForObject($this->getId(), $this->getType());
1332 
1333  if ($version_ids != null && count($version_ids) > 0) {
1334  foreach ($versions as $index => $version) {
1335  if (!in_array($version["hist_entry_id"], $version_ids, true)) {
1336  unset($versions[$index]);
1337  }
1338  }
1339  }
1340 
1341  // add custom entries
1342  foreach ($versions as $index => $version) {
1343  $params = $this->parseInfoParams($version);
1344  $versions[$index] = array_merge($version, $params);
1345  }
1346 
1347  // sort by version number (hist_entry_id will do for that)
1348  usort($versions, array($this, "compareVersions"));
1349 
1350  return $versions;
1351  }
1352 
1353 
1361  public function getSpecificVersion($version_id)
1362  {
1363  include_once("./Services/History/classes/class.ilHistory.php");
1365  if ($version === false) {
1366  return false;
1367  }
1368 
1369  // ilHistory returns different keys in _getEntryByHistoryID and _getEntriesForObject
1370  // so this makes it the same
1371  $version["hist_entry_id"] = $version["id"];
1372  $version["user_id"] = $version["usr_id"];
1373  $version["date"] = $version["hdate"];
1374  unset($version["id"], $version["usr_id"], $version["hdate"]);
1375 
1376  // parse params
1377  $params = $this->parseInfoParams($version);
1378 
1379  return array_merge($version, $params);
1380  }
1381 
1382 
1390  public function rollback($version_id)
1391  {
1392  global $DIC;
1393  $ilDB = $DIC['ilDB'];
1394  $ilUser = $DIC['ilUser'];
1395 
1396  $source = $this->getSpecificVersion($version_id);
1397  if ($source === false) {
1398  $this->ilErr->raiseError($this->lng->txt("obj_not_found"), $this->ilErr->MESSAGE);
1399  }
1400 
1401  // get the new version number
1402  $new_version_nr = $this->getMaxVersion() + 1;
1403  $this->setMaxVersion($new_version_nr);
1404 
1405  // copy file
1406  $source_path = $this->getDirectory($source["version"]) . "/" . $source["filename"];
1407  $dest_dir = $this->getDirectory($new_version_nr);
1408  if (@!is_dir($dest_dir)) {
1409  ilUtil::makeDir($dest_dir);
1410  }
1411 
1412  copy($source_path, $dest_dir . "/" . $source["filename"]);
1413 
1414  // create new history entry based on the old one
1415  include_once("./Services/History/classes/class.ilHistory.php");
1416  // bugfix mantis 26236: added rollback info to version instead of max_version to ensure compatibility with older ilias versions
1417  ilHistory::_createEntry($this->getId(), "rollback", $source["filename"] . ","
1418  . $new_version_nr . "|"
1419  . $source["version"] . "|"
1420  . $ilUser->getId() . ","
1421  . $this->getMaxVersion());
1422 
1423  // get id of newest entry
1424  $entries = ilHistory::_getEntriesForObject($this->getId());
1425  $newest_entry_id = 0;
1426  foreach ($entries as $entry) {
1427  if ($entry["action"] == "rollback") {
1428  $newest_entry_id = $entry["hist_entry_id"];
1429  }
1430  }
1431  $new_version = $this->getSpecificVersion($newest_entry_id);
1432  $new_version['version'] = $new_version_nr;
1433  $new_version['max_version'] = $new_version_nr;
1434 
1435  // change user back to the original uploader
1436  ilHistory::_changeUserId($new_version["hist_entry_id"], $source["user_id"]);
1437 
1438  // update this file with the new version
1439  $this->updateWithVersion($new_version);
1440 
1441  $this->addNewsNotification("file_updated");
1442 
1443  return $new_version;
1444  }
1445 
1446 
1452  protected function updateWithVersion($version)
1453  {
1454  // update title (checkFileExtension must be called before setFileName!)
1455  $this->setTitle($this->checkFileExtension($version["filename"], $this->getTitle()));
1456 
1457  $this->setVersion($version["version"]);
1458  $this->setMaxVersion($version["max_version"]);
1459  $this->setFileName($version["filename"]);
1460 
1461  // evaluate mime type (reset file type before)
1462  $this->setFileType("");
1463  $this->setFileType($this->guessFileType($version["filename"]));
1464 
1465  // set filesize
1466  $this->determineFileSize();
1467 
1468  $this->update();
1469 
1470  // refresh preview
1471  $this->createPreview(true);
1472  }
1473 
1474 
1485  public function compareVersions($v1, $v2)
1486  {
1487  // v2 - v1 because version should be descending
1488  return (int) $v2["version"] - (int) $v1["version"];
1489  }
1490 
1491 
1500  private function parseInfoParams($entry)
1501  {
1502  $data = explode(",", $entry["info_params"]);
1503 
1504  // bugfix: first created file had no version number
1505  // this is a workaround for all files created before the bug was fixed
1506  if (empty($data[1])) {
1507  $data[1] = "1";
1508  }
1509 
1510  if (empty($data[2])) {
1511  $data[2] = "1";
1512  }
1513 
1514 // BEGIN bugfix #27391
1515  if (sizeof($data) > 3)
1516  {
1517  $last = sizeof($data) - 1;
1518  for ($n = 1; $n < $last - 1; $n++)
1519  {
1520  $data[0] .= "," . $data[$n];
1521  }
1522  $data[1] = $data[$last - 1];
1523  $data[2] = $data[$last];
1524  }
1525 // END bugfix #27391
1526 
1527  $result = array(
1528  "filename" => $data[0],
1529  "version" => $data[1],
1530  "max_version" => $data[2],
1531  "rollback_version" => "",
1532  "rollback_user_id" => "",
1533  );
1534 
1535  // if rollback, the version contains the rollback version as well
1536  // bugfix mantis 26236: rollback info is read from version to ensure compatibility with older ilias versions
1537  if ($entry["action"] == "rollback") {
1538  $tokens = explode("|", $result["version"]);
1539  if (count($tokens) > 1) {
1540  $result["version"] = $tokens[0];
1541  $result["rollback_version"] = $tokens[1];
1542 
1543  if (count($tokens) > 2) {
1544  $result["rollback_user_id"] = $tokens[2];
1545  }
1546  }
1547  }
1548 
1549  return $result;
1550  }
1551 
1552 
1553  protected static function handleQuotaUpdate(ilObjFile $a_file)
1554  {
1555  include_once "Services/MediaObjects/classes/class.ilObjMediaObject.php";
1556  $mob = new ilObjMediaObject();
1557 
1558  // file itself could be workspace item
1559  $parent_obj_ids = array($a_file->getId());
1560 
1561  foreach ($a_file->getUsages() as $item) {
1562  $parent_obj_id = $mob->getParentObjectIdForUsage($item);
1563  if ($parent_obj_id
1564  && !in_array($parent_obj_id, $parent_obj_ids)
1565  ) {
1566  $parent_obj_ids[] = $parent_obj_id;
1567  }
1568  }
1569 
1570  include_once "Services/DiskQuota/classes/class.ilDiskQuotaHandler.php";
1571  ilDiskQuotaHandler::handleUpdatedSourceObject($a_file->getType(), $a_file->getId(), $a_file->getDiskUsage(), $parent_obj_ids);
1572  }
1573 
1574 
1581  protected function createPreview($force = false)
1582  {
1583  // only normal files are supported
1584  if ($this->getMode() != self::MODE_OBJECT) {
1585  return;
1586  }
1587 
1588  require_once("./Services/Preview/classes/class.ilPreview.php");
1589  ilPreview::createPreview($this, $force);
1590  }
1591 
1592 
1596  protected function deletePreview()
1597  {
1598  // only normal files are supported
1599  if ($this->getMode() != self::MODE_OBJECT) {
1600  return;
1601  }
1602 
1603  require_once("./Services/Preview/classes/class.ilPreview.php");
1604  ilPreview::deletePreview($this->getId());
1605  }
1606 
1607 
1611  public function setRating($a_value)
1612  {
1613  $this->rating = (bool) $a_value;
1614  }
1615 
1616 
1620  public function hasRating()
1621  {
1622  return $this->rating;
1623  }
1624 
1625 
1629  public function getPageCount()
1630  {
1631  return $this->page_count;
1632  }
1633 
1634 
1638  public function setPageCount($page_count)
1639  {
1640  $this->page_count = $page_count;
1641  }
1642 
1643 
1649  private function getArrayForDatabase($file_id = 0)
1650  {
1651  if ($file_id == 0) {
1652  $file_id = $this->getId();
1653  }
1654  return [
1655  'file_id' => ['integer', $file_id],
1656  'file_name' => ['text', $this->getFileName()],
1657  'file_type' => ['text', $this->getFileType()],
1658  'file_size' => ['integer', (int) $this->getFileSize()],
1659  'version' => ['integer', (int) $this->getVersion()],
1660  'max_version' => ['integer', (int) $this->getMaxVersion()],
1661  'f_mode' => ['text', $this->getMode()],
1662  'page_count' => ['text', $this->getPageCount()],
1663  'rating' => ['integer', $this->hasRating()],
1664  ];
1665  }
1666 }
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static _writeFileType($a_id, $a_format)
setFileType($a_type)
$path
Definition: aliased.php:25
createProperties($a_upload=false)
The basic properties of a file object are stored in table object_data.
static _lookupDiskUsage($a_id)
Returns the number of bytes used on the harddisk by the file object with the specified object id...
setRollbackVersion($a_rollback_version)
static _removeEntryByHistoryID($a_hist_entry_id)
Removes a single entry from the history.
static _isFileInline($a_file_name)
Returns true, if the specified file shall be displayed inline in the browser.
parseInfoParams($entry)
Parses the info parameters ("info_params") of the specified history entry.
$format
Definition: metadata.php:141
static _write($a_type, $a_setting, $a_value, $a_user=0, $a_block_id=0)
Write setting to database.
setFileName($a_name)
static _changeUserId($a_hist_entry_id, $new_user_id)
Changes the user id of the specified history entry.
$result
setMode($a_mode)
mode is object or filelist
static rCopy($a_sdir, $a_tdir, $preserveTimeAttributes=false)
Copies content of a directory $a_sdir recursively to a directory $a_tdir.
global $DIC
Definition: saml.php:7
$_GET["client_id"]
copy($a_source, $a_destination)
copy file
static _isFileHidden($a_file_name)
Returns true, if a file with the specified name, is usually hidden from the user. ...
static _getFileExtension($a_file_name)
Gets the file extension of the specified file name.
clearDataDirectory()
clear data directory
compareVersions($v1, $v2)
Compares two file versions.
getFile($a_hist_entry_id=null)
getMode()
mode is object or filelist
storeUnzipedFile($a_upload_file, $a_filename)
storeUnzipedFile
static _deleteAllUsages($a_type, $a_id, $a_usage_hist_nr=0, $a_usage_lang="-")
static delete all usages of
setVersion($a_version)
doCreateMetaData()
create file object meta data
getDirectory($a_version=0)
$s
Definition: pwgen.php:45
$index
Definition: metadata.php:60
setFileSize($a_size)
$metadata['__DYNAMIC:1__']
setNoMetaDataCreation($a_status)
doCreate($a_upload=false)
create object
static _createEntry( $a_obj_id, $a_action, $a_info_params="", $a_obj_type="", $a_user_comment="", $a_update_last=false)
Creates a new history entry for an object.
static _getEntryByHistoryID($a_hist_entry_id)
returns a single history entry
beforeMDUpdateListener($a_element)
checkFileExtension($new_filename, $new_title)
Check if the file extension does still exist after an update of the title.
static _lookupFileSize($a_id)
Quickly looks up the file size from the database and returns the number of bytes. ...
doUpdateMetaData()
update meta data
static rename($a_source, $a_target)
Rename a file.
replaceFile($a_upload_file, $a_filename)
static getMimeType($a_file='', $a_filename='', $a_mime='')
$a_type
Definition: workflow.php:92
$r
Definition: example_031.php:79
setRollbackUserId($a_rollback_user_id)
static _copyEntriesForObject($a_src_id, $a_dst_id)
copy all history entries for an object
foreach($_POST as $key=> $value) $res
static _lookupFileName($a_id)
static getBytesForString($a_str)
Return string as byte array Note: Use this for debugging purposes only.
addFileVersion($a_upload_file, $a_filename)
const NEWS_NOTICE
setAction($a_action)
const MODE_FILELIST
static createPreview($a_obj, $a_force=false)
Creates the preview for the object with the specified id.
deletePreview()
Deletes the preview of the file object.
$ilUser
Definition: imgupload.php:18
isHidden()
Returns true, if this file should be hidden in the repository view.
Class to report exception.
getArrayForDatabase($file_id=0)
redirection script todo: (a better solution should control the processing via a xml file) ...
Class ilObjMediaObject.
setTitle($a_title)
static _saveUsage($a_file_id, $a_type, $a_id, $a_usage_hist_nr=0, $a_usage_lang="-")
save usage
$n
Definition: RandomTest.php:85
static stripSlashes($a_str, $a_strip_html=true, $a_allow="")
strip slashes if magic qoutes is enabled
isInline()
Returns true, if this file should be displayed inline in a browser window.
createPreview($force=false)
Creates a preview for the file object.
getSpecificVersion($version_id)
Gets a specific file version.
static _getFilesOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_usage_lang="-")
get all files of an object
static _getEntriesForObject($a_obj_id, $a_obj_type="")
get all history entries for an object
addNewsNotification($a_lang_var)
static _lookupType($a_id, $a_reference=false)
lookup object type
getUsages()
get all usages of file object
static makeDir($a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
doCloneObject($a_new_obj, $a_target_id, $a_copy_id=0)
Clone.
$row
setMaxVersion($a_max_version)
static copyPreviews($a_src_id, $a_dest_id)
Copies the preview images from one preview to a new preview object.
const MODE_OBJECT
deleteVersions($a_hist_entry_ids=null)
Deletes the specified history entries or all entries if no ids are specified.
static _lookupFileSize($a_id)
Lookups the file size of the file in bytes.
getFileExtension()
Returns the extension of the file name converted to lower-case.
static handleQuotaUpdate(ilObjFile $a_file)
rollback($version_id)
Makes the specified version the current one and returns theSummary of rollbackVersion.
export($a_target_dir)
export files of object to target directory note: target directory must be the export target directory...
static _lookupVersion($a_id)
lookup version
static escapeShellArg($a_arg)
initFileStorage()
init file storage object
static handleUpdatedSourceObject($a_src_obj_type, $a_src_obj_id, $a_src_filesize, $a_owner_obj_ids=null, $a_is_prtf=false)
Find and update/create all related entries for source object.
Class ilFileDelivery.
setPageCount($page_count)
static deletePreview($a_obj_id)
Deletes the preview for the object with the specified id.
global $ilDB
static _lookupAbsolutePath($obj_id, $a_version=null)
$ret
Definition: parser.php:6
static _getDefaultVisibilityForRefId($a_ref_id)
Get default visibility for reference id.
static _removeEntriesForObject($a_obj_id)
remove all history entries for an object
static getLogger($a_component_id)
Get component logger.
raiseUploadError($a_raise=true)
Class ilFSStorageFile.
const NEWS_USERS
doMDUpdateListener($a_element)
$source
Definition: linkback.php:22
static _lookupVersion($a_id)
lookup version
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
determineFileSize($a_hist_entry_id=null)
Determine File Size.
__construct($a_id=0, $a_call_by_reference=true)
ilObjFile constructor.
getVersions($version_ids=null)
Gets the file versions for this object.
setRating($a_value)
static getValidFilename($a_filename)
Get valid filename.
guessFileType($a_file="")
Guesses the file type based on the current values returned by getFileType() and getFileExtension().
updateWithVersion($version)
Updates the file object with the specified file version.
cloneMetaData($target_obj)
$data
Definition: bench.php:6
getDiskUsage()
Gets the disk usage of the object in bytes.