ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilFileXMLParser.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4
18
19include_once './Services/Xml/classes/class.ilSaxParser.php';
20include_once 'Modules/File/classes/class.ilFileException.php';
21include_once 'Services/Utilities/classes/class.ilFileUtils.php';
22
24{
25 public static $CONTENT_NOT_COMPRESSED = 0;
26 public static $CONTENT_GZ_COMPRESSED = 1;
27 public static $CONTENT_ZLIB_COMPRESSED = 2;
28 public static $CONTENT_COPY = 4;
29 // begin-patch fm
30 public static $CONTENT_REST = 5;
31 // end-patch fm
37 public $file;
44 public $obj_id;
50 public $result;
56 public $mode;
62 //var $content;
63
75 //var $content;
76
80 protected $version = null;
84 protected $action = null;
88 protected $rollback_version = null;
92 protected $rollback_user_id = null;
96 protected $max_version = null;
100 protected $date = null;
104 protected $usr_id = null;
108 protected $versions = [];
109
110
120 public function __construct($file, $a_xml_data, $obj_id = -1, $mode = 0)
121 {
122 parent::__construct();
123 $this->file = $file;
124 $this->setXMLContent($a_xml_data);
125 $this->obj_id = $obj_id;
126 $this->result = false;
127 $this->mode = $mode;
128 }
129
130
136 public function setImportDirectory($a_val)
137 {
138 $this->importDirectory = $a_val;
139 }
140
141
147 public function getImportDirectory()
148 {
149 return $this->importDirectory;
150 }
151
152
160 public function setHandlers($a_xml_parser)
161 {
162 xml_set_object($a_xml_parser, $this);
163 xml_set_element_handler($a_xml_parser, 'handlerBeginTag', 'handlerEndTag');
164 xml_set_character_data_handler($a_xml_parser, 'handlerCharacterData');
165 }
166
167
178 public function handlerBeginTag($a_xml_parser, $a_name, $a_attribs)
179 {
180 global $DIC;
181 $ilErr = $DIC['ilErr'];
182
183 global $DIC;
184 $ilLog = $DIC['ilLog'];
185
186 switch ($a_name) {
187 case 'File':
188 if (isset($a_attribs["obj_id"])) {
189 $read_obj_id = ilUtil::__extractId($a_attribs["obj_id"], IL_INST_ID);
190 if ($this->obj_id != -1 && (int) $read_obj_id != -1 && (int) $this->obj_id != (int) $read_obj_id) {
191 throw new ilFileException(
192 "Object IDs (xml $read_obj_id and argument " . $this->obj_id . ") do not match!",
194 );
195 }
196 }
197 if (isset($a_attribs["type"])) {
198 $this->file->setFileType($a_attribs["type"]);
199 }
200 $this->file->setVersion($a_attribs["version"]); // Selected version
201 $this->file->setMaxVersion($a_attribs["max_version"]);
202 $this->file->setAction($a_attribs["action"]);
203 $this->file->setRollbackVersion($a_attribs["rollback_version"]);
204 $this->file->setRollbackUserId($a_attribs["rollback_user_id"]);
205 break;
206 case 'Content': // Old import files
207 case 'Version':
208 if ($a_name === "Version" && !isset($a_attribs["mode"])) {
209 // Old import files
210 $this->version = null;
211 if ($this->date === null) {
212 // Version tag comes after Content tag. Take only first (= Should be latest)
213 $this->date = $a_attribs["date"];
214 $this->usr_id = $a_attribs["usr_id"];
215 $this->versions[0]["date"] = $this->date;
216 $this->versions[0]["usr_id"] = $this->usr_id;
217 }
218 break;
219 }
220
222 $this->isReadingFile = true;
223 $this->tmpFilename = ilUtil::ilTempnam();
224 #echo $a_attribs["mode"];
225 if (isset($a_attribs["mode"])) {
226 if ($a_attribs["mode"] == "GZIP") {
227 if (!function_exists("gzread")) {
228 throw new ilFileException("Deflating with gzip is not supported", ilFileException::$ID_DEFLATE_METHOD_MISMATCH);
229 }
230
232 } elseif ($a_attribs["mode"] == "ZLIB") {
233 if (!function_exists("gzuncompress")) {
234 throw new ilFileException("Deflating with zlib (compress/uncompress) is not supported", ilFileException::$ID_DEFLATE_METHOD_MISMATCH);
235 }
236
238 } elseif ($a_attribs["mode"] == "COPY") {
239 $this->mode = ilFileXMLParser::$CONTENT_COPY;
240 } // begin-patch fm
241 elseif ($a_attribs['mode'] == 'REST') {
242 $this->mode = ilFileXMLParser::$CONTENT_REST;
243 }
244 // end-patch fm
245 }
246
247 if ($a_name === "Version") {
248 $this->version = $a_attribs["version"];
249 $this->max_version = $a_attribs["max_version"];
250 $this->date = $a_attribs["date"];
251 $this->usr_id = $a_attribs["usr_id"];
252 $this->action = $a_attribs["action"];
253 $this->rollback_version = $a_attribs["rollback_version"];
254 $this->rollback_user_id = $a_attribs["rollback_user_id"];
255 } else {
256 // Old import files
257 //$this->version = $this->file->getVersion();
258 $this->version = 1;
259 $this->file->setVersion($this->version);
260 }
261 }
262 }
263
264
271 public function handlerEndTag($a_xml_parser, $a_name)
272 {
273 $this->cdata = trim($this->cdata);
274
275 $GLOBALS['DIC']['ilLog']->write(__METHOD__ . ': ' . $this->cdata);
276
277 switch ($a_name) {
278 case 'File':
279 $this->result = true;
280 break;
281 case 'Filename':
282 if (strlen($this->cdata) == 0) {
283 throw new ilFileException("Filename ist missing!");
284 }
285
286 $this->file->setFilename(basename(self::normalizeRelativePath($this->cdata)));
287 $this->file->setTitle($this->cdata);
288
289 break;
290 case 'Title':
291 $this->file->setTitle(trim($this->cdata));
292 break;
293 case 'Description':
294 $this->file->setDescription(trim($this->cdata));
295 break;
296 case 'Rating':
297 $this->file->setRating((bool) $this->cdata);
298 break;
299 case 'Content': // Old import files
300 case 'Version':
301 if ($a_name === "Version" && $this->version === null) {
302 // Old import files
303 break;
304 }
305
306 $GLOBALS['DIC']['ilLog']->write($this->mode);
307 $this->isReadingFile = false;
308 $baseDecodedFilename = ilUtil::ilTempnam();
309 if ($this->mode == ilFileXMLParser::$CONTENT_COPY) {
310 $this->tmpFilename = $this->getImportDirectory() . "/" . self::normalizeRelativePath($this->cdata);
311 } // begin-patch fm
312 elseif ($this->mode == ilFileXMLParser::$CONTENT_REST) {
313 include_once './Services/WebServices/Rest/classes/class.ilRestFileStorage.php';
314 $storage = new ilRestFileStorage();
315 $this->tmpFilename = $storage->getStoredFilePath(self::normalizeRelativePath($this->cdata));
316 if (!ilFileUtils::fastBase64Decode($this->tmpFilename, $baseDecodedFilename)) {
317 throw new ilFileException("Base64-Decoding failed", ilFileException::$DECOMPRESSION_FAILED);
318 }
319 $this->tmpFilename = $baseDecodedFilename;
320 } // end-patch fm
321 else {
322 if (!ilFileUtils::fastBase64Decode($this->tmpFilename, $baseDecodedFilename)) {
323 throw new ilFileException("Base64-Decoding failed", ilFileException::$DECOMPRESSION_FAILED);
324 }
325 if ($this->mode == ilFileXMLParser::$CONTENT_GZ_COMPRESSED) {
326 if (!ilFileUtils::fastGunzip($baseDecodedFilename, $this->tmpFilename)) {
327 throw new ilFileException("Deflating with fastzunzip failed", ilFileException::$DECOMPRESSION_FAILED);
328 }
329 unlink($baseDecodedFilename);
330 } elseif ($this->mode == ilFileXMLParser::$CONTENT_ZLIB_COMPRESSED) {
331 if (!ilFileUtils::fastGunzip($baseDecodedFilename, $this->tmpFilename)) {
332 throw new ilFileException("Deflating with fastDecompress failed", ilFileException::$DECOMPRESSION_FAILED);
333 }
334 unlink($baseDecodedFilename);
335 } else {
336 $this->tmpFilename = $baseDecodedFilename;
337 }
338 }
339
340 if ($this->version == $this->file->getVersion()) {
341 global $DIC;
342 $rel = LegacyPathHelper::createRelativePath($this->tmpFilename);
343 if ($DIC->filesystem()->temp()->has($rel)) {
344 $this->file->setFileSize($DIC->filesystem()->temp()->getSize($rel, DataSize::Byte)->getSize());
345 } else {
346 $array = $DIC->filesystem()->temp()->listContents(dirname($rel));
347 $first_file = reset($array);
348
349 if ($first_file instanceof \ILIAS\Filesystem\DTO\Metadata) {
350 $this->file->setFileSize($DIC->filesystem()->temp()->getSize($first_file->getPath(),
351 DataSize::Byte)->getSize());
352 }
353 }
354
355 // if no file type is given => lookup mime type
356 if (!$this->file->getFileType()) {
357 global $DIC;
358 $ilLog = $DIC['ilLog'];
359
360 #$ilLog->write(__METHOD__.': Trying to detect mime type...');
361 include_once('./Services/Utilities/classes/class.ilFileUtils.php');
362 $this->file->setFileType(ilFileUtils::_lookupMimeType($this->tmpFilename));
363 }
364 }
365
366 $this->versions[] = [
367 "version" => $this->version,
368 "max_version" => $this->max_version,
369 "tmpFilename" => $this->tmpFilename,
370 "date" => $this->date,
371 "usr_id" => $this->usr_id,
372 "action" => $this->action,
373 "rollback_version" => $this->rollback_version,
374 "rollback_user_id" => $this->rollback_user_id,
375 ];
376 $this->version = null;
377 $this->date = null;
378 $this->usr_id = null;
379 break;
380 }
381
382 $this->cdata = '';
383
384 return;
385 }
386
387
394 public function handlerCharacterData($a_xml_parser, $a_data)
395 {
396 if ($a_data != "\n") {
397 // begin-patch fm
398 if ($this->isReadingFile && $this->mode != ilFileXMLParser::$CONTENT_COPY
399 && $this->mode != ilFileXMLParser::$CONTENT_REST
400 ) { // begin-patch fm
401 $handle = fopen($this->tmpFilename, "a");
402 fwrite($handle, $a_data);
403 fclose($handle);
404 } else {
405 $this->cdata .= $a_data;
406 }
407 }
408 }
409
410
416 public function setFileContents()
417 {
418 // Delete exists version 1 history
419 ilHistory::_removeEntriesForObject($this->file->getId());
420
421 foreach ($this->versions as $version) {
422 if (!file_exists($version["tmpFilename"])) {
423 // try to get first file of dir
424 $files = scandir(dirname($version["tmpFilename"]));
425 $version["tmpFilename"] = rtrim(dirname($version["tmpFilename"]),
426 "/") . "/" . $files[2];// because [0] = "." [1] = ".."
427 if (!file_exists($version["tmpFilename"])) {
428 ilLoggerFactory::getLogger('file')->error(__METHOD__ . ' "' . ($version["tmpFilename"]) . '" file not found.');
429
430 continue;
431 }
432 }
433
434 if (filesize($version["tmpFilename"]) == 0) {
435 continue;
436 }
437
438 $filedir = $this->file->getDirectory($version["version"]);
439
440 if (!is_dir($filedir)) {
441 $this->file->createDirectory();
442 ilUtil::makeDir($filedir);
443 }
444
445 $filename = $filedir . "/" . $this->file->getFileName();
446
447 if (file_exists($filename)) {
448 unlink($filename);
449 }
450
451 ilFileUtils::rename($version["tmpFilename"], $filename);
452
453 // Add version history
454 // bugfix mantis 26236: add rollback info to version instead of max_version to ensure compatibility with older ilias versions
455 if ($version["rollback_version"] != "" and $version["rollback_version"] != null
456 and $version["rollback_user_id"] != "" and $version["rollback_user_id"] != null
457 ) {
458 ilHistory::_createEntry($this->file->getId(), $version["action"], basename($filename) . ","
459 . $version["version"] . "|"
460 . $version["rollback_version"] . "|"
461 . $version["rollback_user_id"] . ","
462 . $version["max_version"]);
463 } else {
464 if ($version["action"] != "" and $version["action"] != null) {
465 ilHistory::_createEntry($this->file->getId(), $version["action"], basename($filename) . ","
466 . $version["version"] . ","
467 . $version["max_version"]);
468 } else {
469 ilHistory::_createEntry($this->file->getId(), "new_version", basename($filename) . ","
470 . $version["version"] . ","
471 . $version["max_version"]);
472 }
473 }
474 }
475 }
476
477
483 public function updateFileContents()
484 {
485 if ($this->setFileContents()) {
486 require_once("./Services/History/classes/class.ilHistory.php");
487 if ($this->file->getRollbackVersion() != "" and $this->file->getRollbackVersion() != null
488 and $this->file->getRollbackUserId() != "" and $this->file->getRollbackUserId() != null
489 ) {
490 ilHistory::_createEntry($this->file->getId(), $this->file->getAction(), $this->file->getFilename() . "," . $this->file->getVersion() . "," . $this->file->getMaxVersion()
491 . "|" . $this->file->getRollbackVersion() . "|" . $this->file->getRollbackUserId());
492 } else {
493 if ($this->file->getAction() != "" and $this->file->getAction() != null) {
494 ilHistory::_createEntry($this->file->getId(), $this->file->getAction(), $this->file->getFilename() . "," . $this->file->getVersion() . "," . $this->file->getMaxVersion());
495 } else {
496 ilHistory::_createEntry($this->file->getId(), "replace", $this->file->getFilename() . "," . $this->file->getVersion() . "," . $this->file->getMaxVersion());
497 }
498 }
499 $this->file->addNewsNotification("file_updated");
500 }
501 }
502
503
511 public function start()
512 {
513 $this->startParsing();
514
515 return $this->result > 0;
516 }
517
518
531 public static function normalizeRelativePath($path)
532 {
533 $path = str_replace('\\', '/', $path);
534
535 while (preg_match('#\p{C}+|^\./#u', $path)) {
536 $path = preg_replace('#\p{C}+|^\./#u', '', $path);
537 }
538
539 $parts = [];
540 foreach (explode('/', $path) as $part) {
541 switch ($part) {
542 case '':
543 case '.':
544 break;
545 case '..':
546 array_pop($parts);
547 break;
548 default:
549 $parts[] = $part;
550 break;
551 }
552 }
553
554 return implode('/', $parts);
555 }
556}
$path
Definition: aliased.php:25
$filename
Definition: buildRTE.php:89
An exception for terminatinating execution or to throw for unit testing.
Class DataSize.
Definition: DataSize.php:16
Class to report exception.
fastGunzip($in, $out)
fast uncompressing the file with the zlib-extension without memory consumption
static _lookupMimeType($a_file)
static fastBase64Decode($filein, $fileout)
decodes base encoded file row by row to prevent memory exhaust
static rename($a_source, $a_target)
Rename a file.
getImportDirectory()
Get import directory.
setHandlers($a_xml_parser)
set event handlers
setFileContents()
update file according to filename and version, does not update history has to be called after (!...
updateFileContents()
update file according to filename and version and create history entry has to be called after (!...
handlerEndTag($a_xml_parser, $a_name)
handler for end of element
handlerBeginTag($a_xml_parser, $a_name, $a_attribs)
handler for begin of element
setImportDirectory($a_val)
Set import directory.
start()
starts parsing an changes object by side effect.
__construct($file, $a_xml_data, $obj_id=-1, $mode=0)
Constructor.
handlerCharacterData($a_xml_parser, $a_data)
handler for character data
static normalizeRelativePath($path)
Normalize relative directories in a path.
static _removeEntriesForObject($a_obj_id)
remove all history entries for an 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 getLogger($a_component_id)
Get component logger.
File storage handling.
Base class for sax-based expat parsing extended classes need to overwrite the method setHandlers and ...
setXMLContent($a_xml_content)
startParsing()
stores xml data in array
static ilTempnam($a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
static __extractId($ilias_id, $inst_id)
extract ref id from role title, e.g.
static makeDir($a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
$files
Definition: metarefresh.php:49
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
Class FlySystemFileAccessTest.
Class BaseForm.
$ilErr
Definition: raiseError.php:18
global $DIC
Definition: saml.php:7