ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.ilObjFileDAV.php
Go to the documentation of this file.
1<?php
2use Sabre\DAV\Exception;
3use Sabre\DAV\Exception\Forbidden;
4
5require_once 'Modules/File/classes/class.ilObjFile.php';
6
19{
25 protected $obj;
26
33
45 {
46 $settings = new ilSetting('file_access');
47 $this->versioning_enabled = (bool) $settings->get('webdav_versioning_enabled', true);
49 }
50
72 public function put($data)
73 {
74 if ($this->repo_helper->checkAccess('write', $this->getRefId())) {
76 if ($this->versioning_enabled === true) {
77 // Stolen from ilObjFile->addFileVersion
78 $this->handleFileUpload($data, 'new_version');
79 } else {
80 $this->handleFileUpload($data, 'replace');
81 }
82
83
84 return $this->getETag();
85 }
86 throw new Exception\Forbidden("Permission denied. No write access for this file");
87 }
88
97 public function get()
98 {
99 if ($this->repo_helper->checkAccess("read", $this->obj->getRefId())) {
100 $file = $this->getPathToFile();
101
102 if (file_exists($file)) {
103 return fopen($file, 'r');
104 } else {
105 throw new Exception\NotFound("File not found");
106 }
107 }
108
109 throw new Exception\Forbidden("Permission denied. No read access for this file");
110 }
111
117 public function getName()
118 {
119 return ilFileUtils::getValidFilename($this->obj->getTitle());
120 }
121
129 public function getContentType()
130 {
131 return $this->obj->guessFileType();
132 }
133
148 public function getETag()
149 {
150 if (file_exists($path = $this->getPathToFile())) {
151 return '"' . sha1(
152 fileinode($path) .
153 filesize($path) .
154 filemtime($path)
155 ) . '"';
156 }
157
158 return null;
159 }
160
166 public function getSize()
167 {
168 if (file_exists($this->getPathToFile())) {
169 return $this->obj->getFileSize();
170 }
171 return 0;
172 }
173
178 public function setName($a_name)
179 {
180 if ($this->dav_helper->isValidFileNameWithValidFileExtension($a_name)) {
181 parent::setName($a_name);
182 } else {
183 throw new Exception\Forbidden("Invalid file extension");
184 }
185 }
186
196 public function handleFileUpload($a_data, $a_file_action)
197 {
198 // Set name for uploaded file because due to the versioning, the title can change for different versions. This setter-call here
199 // ensures that the uploaded file is saved with the title of the object. This obj->setFileName() has to be called
200 // before $this->getPathToFile(). Otherwise, the file could be saved under the wrong filename.
201 if ($a_file_action === 'replace') {
202 $this->obj->deleteVersions();
203 $this->obj->clearDataDirectory();
204 }
205 $this->obj->setFileName($this->getName());
206 $file_dest_path = $this->getPathToFile();
207
208 // If dir does not exist yet -> create it
209 if (!file_exists($file_dest_path)) {
211 }
212
213 $written_length = $this->uploadFile($a_data, $file_dest_path);
214
215 if ($written_length > ilUtil::getUploadSizeLimitBytes()) {
216 $this->deleteObjOrVersion();
217 throw new Exception\Forbidden('File is too big');
218 }
219
220 // Security checks
221 $this->checkForVirus($file_dest_path);
222
223 // Set last meta data
224 $this->obj->setFileType(ilMimeTypeUtil::lookupMimeType($file_dest_path));
225 $this->obj->setFileSize($written_length);
226 if ($this->obj->update()) {
227 $this->createHistoryAndNotificationForObjUpdate($a_file_action);
228 ilPreview::createPreview($this->obj, true);
229 }
230 }
231
240 protected function uploadFile($a_data, string $file_dest_path)
241 {
242 $written_length = file_put_contents($file_dest_path, $a_data);
243 if ($written_length === false && strlen($a_data) > 0) {
244 throw new Exception\Forbidden('Forbidden to write file');
245 }
246 return $written_length;
247 }
248
249 protected function getPathToDirectory()
250 {
251 return $this->obj->getDirectory($this->obj->getVersion());
252 }
253
263 protected function getPathToFile()
264 {
265 // ilObjFile delivers the filename like it was on the upload. But if the file-extension is forbidden, the file
266 // will be safed as .sec-file. In this case ->getFileName returns the wrong file name
267 $path = $this->getPathToDirectory() . "/" . $this->obj->getFileName();
268
269 // For the case of forbidden file-extensions, ::getValidFilename($path) returns the path with the .sec extension
270 return ilFileUtils::getValidFilename($path);
271 }
272
273 protected function checkForVirus(string $file_dest_path)
274 {
275 $vrs = ilUtil::virusHandling($file_dest_path, '', true);
276 // If vrs[0] == false -> virus found
277 if ($vrs[0] == false) {
278 ilLoggerFactory::getLogger('WebDAV')->error(get_class($this) . ' ' . $this->obj->getTitle() . " -> virus found on '$file_dest_path'!");
279 $this->deleteObjOrVersion();
280 throw new Exception\Forbidden('Virus found!');
281 }
282 }
283
287 protected function setObjValuesForNewFileVersion()
288 {
289 // This is necessary for windows explorer. Because windows explorer makes always 2 PUT requests. One with a 0 Byte
290 // file to test, if the user has write permissions and the second one to upload the original file.
291 if ($this->obj->getFileSize() > 0) {
292 // Stolen from ilObjFile->addFileVersion
293 $this->obj->setVersion($this->obj->getMaxVersion() + 1);
294 $this->obj->setMaxVersion($this->obj->getMaxVersion() + 1);
295 }
296 }
297
303 protected function createHistoryAndNotificationForObjUpdate($a_action)
304 {
305 // Add history entry and notification for new file version (stolen from ilObjFile->addFileVersion)
306 switch ($a_action) {
307 case "new_version":
308 case "replace":
309 ilHistory::_createEntry($this->obj->getId(), $a_action, $this->obj->getTitle() . "," . $this->obj->getVersion() . "," . $this->obj->getMaxVersion());
310 break;
311 }
312
313 $this->obj->addNewsNotification("file_updated");
314 }
315
319 protected function deleteObjOrVersion()
320 {
321 if ($this->obj->getVersion() > 1) {
322 $version_dir = $this->obj->getDirectory($this->obj->getVersion());
323 ilUtil::delDir($version_dir);
324 } else {
325 $this->obj->deleteVersions();
326 $this->obj->delete();
327 }
328 }
329}
An exception for terminatinating execution or to throw for unit testing.
static getValidFilename($a_filename)
Get valid filename.
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 getLogger($a_component_id)
Get component logger.
static lookupMimeType($path_to_file, $fallback=self::APPLICATION__OCTET_STREAM, $a_external=null)
Class ilObjFileDAV.
getSize()
Returns the size of the node, in bytes.
getName()
Returns title of file object.
deleteObjOrVersion()
Delete an object if there is no other version in it otherwise delete version.
put($data)
Replaces the contents of the file.
setObjValuesForNewFileVersion()
Set object values for a new file version.
__construct(ilObjFile $a_obj, ilWebDAVRepositoryHelper $repo_helper, ilWebDAVObjDAVHelper $dav_helper)
ilObjFileDAV represents the WebDAV-Interface to an ILIAS-Object
getContentType()
Returns the mime-type for a file.
uploadFile($a_data, string $file_dest_path)
Write given data (as string) to the given file.
handleFileUpload($a_data, $a_file_action)
Handle uploaded file.
checkForVirus(string $file_dest_path)
createHistoryAndNotificationForObjUpdate($a_action)
Create history entry and a news notification for file object update.
getETag()
Returns the ETag for a file.
getPathToFile()
This method is called in 2 use cases:
Class ilObjFile.
Class ilObjectDAV.
static createPreview($a_obj, $a_force=false)
Creates the preview for the object with the specified id.
ILIAS Setting Class.
static delDir($a_dir, $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static getUploadSizeLimitBytes()
static virusHandling($a_file, $a_orig_name="", $a_clean=true)
scan file for viruses and clean files if possible
static makeDirParents($a_dir)
Create a new directory and all parent directories.
Class ilWebDAVObjDAVHelper.
Class ilWebDAVRepositoryHelper.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$data
Definition: storeScorm.php:23