ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
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 {
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 if ($version["rollback_version"] != "" and $version["rollback_version"] != null
455 and $version["rollback_user_id"] != "" and $version["rollback_user_id"] != null
456 ) {
457 ilHistory::_createEntry($this->file->getId(), $version["action"], basename($filename) . "," . $version["version"] . "," . $version["max_version"]
458 . "|" . $version["rollback_version"] . "|" . $version["rollback_user_id"]);
459 } else {
460 if ($version["action"] != "" and $version["action"] != null) {
461 ilHistory::_createEntry($this->file->getId(), $version["action"], basename($filename) . "," . $version["version"] . "," . $version["max_version"]);
462 } else {
463 ilHistory::_createEntry($this->file->getId(), "new_version", basename($filename) . "," . $version["version"] . "," . $version["max_version"]);
464 }
465 }
466 }
467 }
468
469
475 public function updateFileContents()
476 {
477 if ($this->setFileContents()) {
478 require_once("./Services/History/classes/class.ilHistory.php");
479 if ($this->file->getRollbackVersion() != "" and $this->file->getRollbackVersion() != null
480 and $this->file->getRollbackUserId() != "" and $this->file->getRollbackUserId() != null
481 ) {
482 ilHistory::_createEntry($this->file->getId(), $this->file->getAction(), $this->file->getFilename() . "," . $this->file->getVersion() . "," . $this->file->getMaxVersion()
483 . "|" . $this->file->getRollbackVersion() . "|" . $this->file->getRollbackUserId());
484 } else {
485 if ($this->file->getAction() != "" and $this->file->getAction() != null) {
486 ilHistory::_createEntry($this->file->getId(), $this->file->getAction(), $this->file->getFilename() . "," . $this->file->getVersion() . "," . $this->file->getMaxVersion());
487 } else {
488 ilHistory::_createEntry($this->file->getId(), "replace", $this->file->getFilename() . "," . $this->file->getVersion() . "," . $this->file->getMaxVersion());
489 }
490 }
491 $this->file->addNewsNotification("file_updated");
492 }
493 }
494
495
503 public function start()
504 {
505 $this->startParsing();
506
507 return $this->result > 0;
508 }
509
510
523 public static function normalizeRelativePath($path)
524 {
525 $path = str_replace('\\', '/', $path);
526
527 while (preg_match('#\p{C}+|^\./#u', $path)) {
528 $path = preg_replace('#\p{C}+|^\./#u', '', $path);
529 }
530
531 $parts = [];
532 foreach (explode('/', $path) as $part) {
533 switch ($part) {
534 case '':
535 case '.':
536 break;
537 case '..':
538 array_pop($parts);
539 break;
540 default:
541 $parts[] = $part;
542 break;
543 }
544 }
545
546 return implode('/', $parts);
547 }
548}
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
Definition: PEAR.php:64
$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 ...
Class FlySystemFileAccessTest.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
Class ChatMainBarProvider \MainMenu\Provider.
$ilErr
Definition: raiseError.php:18
$DIC
Definition: xapitoken.php:46