1<?php 2/* Copyright (c) 1998-2012 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4class ilForumXMLParser extends ilSaxParser 5{ 6 /** 7 * 8 * An instance of ilObjForum 9 * 10 * @var ilObjForum 11 */ 12 private $forum; 13 private $entity; 14 private $mapping = array( 15 'frm' => array(), 16 'thr' => array(), 17 'pos' => array() 18 ); 19 private $import_install_id = null; 20 private $user_id_mapping = array(); 21 protected $mediaObjects = array(); 22 23 /** 24 * @var null|string 25 */ 26 protected $schema_version = null; 27 28 private $db; 29 /** 30 * Constructor 31 * 32 * @param ilObjForum $forum existing forum object 33 * @param string $a_xml_file xml data 34 * @access public 35 */ 36 public function __construct($forum, $a_xml_data) 37 { 38 global $DIC; 39 40 parent::__construct(); 41 $this->forum = $forum; 42 $this->setXMLContent('<?xml version="1.0" encoding="utf-8"?>' . $a_xml_data); 43 $this->aobject = new ilObjUser(ANONYMOUS_USER_ID); 44 $this->db = $DIC->database(); 45 } 46 47 /** 48 * Set import directory 49 * 50 * @param string import directory 51 */ 52 public function setImportDirectory($a_val) 53 { 54 $this->importDirectory = $a_val; 55 } 56 57 /** 58 * Get import directory 59 * 60 * @return string import directory 61 */ 62 public function getImportDirectory() 63 { 64 return $this->importDirectory; 65 } 66 67 /** 68 * @return null|string 69 */ 70 public function getSchemaVersion() 71 { 72 return $this->schema_version; 73 } 74 75 /** 76 * @param null|string $schema_version 77 */ 78 public function setSchemaVersion($schema_version) 79 { 80 $this->schema_version = $schema_version; 81 } 82 83 /** 84 * set event handlers 85 * 86 * @param resource reference to the xml parser 87 * @access private 88 */ 89 public function setHandlers($a_xml_parser) 90 { 91 xml_set_object($a_xml_parser, $this); 92 xml_set_element_handler($a_xml_parser, 'handlerBeginTag', 'handlerEndTag'); 93 xml_set_character_data_handler($a_xml_parser, 'handlerCharacterData'); 94 } 95 96 /** 97 * handler for begin of element 98 * 99 * @param resource $a_xml_parser xml parser 100 * @param string $a_name element name 101 * @param array $a_attribs element attributes array 102 */ 103 public function handlerBeginTag($a_xml_parser, $a_name, $a_attribs) 104 { 105 switch ($a_name) { 106 case 'Forum': 107 $this->entity = 'forum'; 108 $this->forumArray = array(); 109 break; 110 111 case 'Thread': 112 $this->entity = 'thread'; 113 $this->threadArray = array(); 114 break; 115 116 case 'Post': 117 $this->mediaObjects = array(); 118 $this->entity = 'post'; 119 $this->postArray = array(); 120 break; 121 122 case 'Content': 123 $this->entity = 'content'; 124 $this->contentArray = array(); 125 break; 126 127 case 'MediaObject': 128 $this->mediaObjects[] = $a_attribs; 129 break; 130 } 131 } 132 133 /** 134 * handler for end of element 135 * 136 * @param resource $a_xml_parser xml parser 137 * @param string $a_name element name 138 */ 139 public function handlerEndTag($a_xml_parser, $a_name) 140 { 141 $this->cdata = trim($this->cdata); 142 $arrayname = strtolower($this->entity) . 'Array'; 143 $x = &$this->$arrayname; 144 145 switch ($a_name) { 146 case 'Forum': 147 $query_num_posts = "SELECT COUNT(pos_pk) cnt 148 FROM frm_posts 149 WHERE pos_top_fk = " . $this->db->quote( 150 $this->lastHandledForumId, 151 'integer' 152 ); 153 154 $res_pos = $this->db->query($query_num_posts); 155 $data_pos = $this->db->fetchAssoc($res_pos); 156 $num_posts = $data_pos['cnt']; 157 158 $query_num_threads = "SELECT COUNT(thr_pk) cnt 159 FROM frm_threads 160 WHERE thr_top_fk = " . $this->db->quote( 161 $this->lastHandledForumId, 162 'integer' 163 ); 164 165 $res_thr = $this->db->query($query_num_threads); 166 $data_thr = $this->db->fetchAssoc($res_thr); 167 $num_threads = $data_thr['cnt']; 168 169 $update_str = "$this->lastHandledForumId#$this->lastHandledThreadId#$this->lastHandledPostId"; 170 $this->db->manipulateF( 171 "UPDATE frm_data 172 SET top_last_post = %s, 173 top_num_posts = %s, 174 top_num_threads = %s, 175 top_usr_id = %s 176 WHERE top_frm_fk = %s", 177 array('text', 'integer', 'integer', 'integer', 'integer'), 178 array($update_str, $num_posts, $num_threads, $this->frm_last_mapped_top_usr_id, $this->forum_obj_id) 179 ); 180 break; 181 182 case 'Id': 183 $x['Id'] = $this->cdata; 184 break; 185 186 case 'ObjId': 187 $x['ObjId'] = $this->cdata; 188 break; 189 190 case 'Title': 191 $x['Title'] = $this->cdata; 192 break; 193 194 case 'Description': 195 $x['Description'] = $this->cdata; 196 break; 197 198 case 'DefaultView': 199 $x['DefaultView'] = $this->cdata; 200 break; 201 202 case 'Pseudonyms': 203 $x['Pseudonyms'] = $this->cdata; 204 break; 205 206 case 'Statistics': 207 $x['Statistics'] = $this->cdata; 208 break; 209 210 case 'ThreadRatings': 211 $x['ThreadRatings'] = $this->cdata; 212 break; 213 214 case 'PostingActivation': 215 $x['PostingActivation'] = $this->cdata; 216 break; 217 218 case 'PresetSubject': 219 $x['PresetSubject'] = $this->cdata; 220 break; 221 222 case 'PresetRe': 223 $x['PresetRe'] = $this->cdata; 224 break; 225 226 case 'NotificationType': 227 $x['NotificationType'] = $this->cdata; 228 break; 229 230 case 'ForceNotification': 231 $x['ForceNotification'] = $this->cdata; 232 break; 233 234 case 'ToggleNotification': 235 $x['ToggleNotification'] = $this->cdata; 236 break; 237 238 case 'LastPost': 239 $x['LastPost'] = $this->cdata; 240 break; 241 242 case 'Moderator': 243 $x['Moderator'] = $this->cdata; 244 break; 245 246 case 'CreateDate': 247 $x['CreateDate'] = $this->cdata; 248 break; 249 250 case 'UpdateDate': 251 $x['UpdateDate'] = $this->cdata; 252 break; 253 254 case 'FileUpload': 255 $x['FileUpload'] = $this->cdata; 256 break; 257 258 case 'UpdateUserId': 259 $x['UpdateUserId'] = $this->cdata; 260 break; 261 262 case 'AuthorId': 263 $x['AuthorId'] = $this->cdata; 264 break; 265 case 'isAuthorModerator': 266 $x['isAuthorModerator'] = $this->cdata; 267 break; 268 269 case 'UserId': 270 $x['UserId'] = $this->cdata; 271 if ($this->entity == 'forum' && $this->forumArray) { 272 //// @todo: Maybe problems if the forum xml is imported as content of a course 273 // createSettings accesses superglobal $_GET array, which can cause problems 274 // with public_notifications of block settings 275 $this->forum->createSettings(); 276 277 $forum_array = $this->getUserIdAndAlias( 278 $this->forumArray['UserId'], 279 '' 280 ); 281 282 $this->frm_last_mapped_top_usr_id = $forum_array['usr_id']; 283 284 $update_forum_array = $this->getUserIdAndAlias( 285 $this->forumArray['UpdateUserId'], 286 '' 287 ); 288 // Store old user id 289 // Manipulate user object 290 // changed smeyer 28.7.16: the session id is not manipulated 291 // anymore. Instead the user is passwd ilObjForum::update() 292 $this->forum->setTitle($this->forumArray["Title"]); 293 $this->forum->setDescription($this->forumArray["Description"]); 294 $this->forum->update($update_forum_array['usr_id']); 295 296 // create frm_settings 297 $newObjProp = ilForumProperties::getInstance($this->forum->getId()); 298 $newObjProp->setDefaultView((int) $this->forumArray['DefaultView']); 299 $newObjProp->setAnonymisation((int) $this->forumArray['Pseudonyms']); 300 $newObjProp->setStatisticsStatus((int) $this->forumArray['Statistics']); 301 $newObjProp->setIsThreadRatingEnabled((int) $this->forumArray['ThreadRatings']); 302 $newObjProp->setPostActivation((int) $this->forumArray['PostingActivation']); 303 $newObjProp->setPresetSubject((int) $this->forumArray['PresetSubject']); 304 $newObjProp->setAddReSubject((int) $this->forumArray['PresetRe']); 305 $newObjProp->setNotificationType($this->forumArray['NotificationType'] ? $this->forumArray['NotificationType'] : 'all_users'); 306 $newObjProp->setAdminForceNoti((int) $this->forumArray['ForceNotification']); 307 $newObjProp->setUserToggleNoti((int) $this->forumArray['ToggleNotification']); 308 $newObjProp->setFileUploadAllowed((int) $this->forumArray['FileUpload']); 309 $newObjProp->setThreadSorting((int)$this->forumArray['Sorting']); 310 $newObjProp->setMarkModeratorPosts((int)$this->forumArray['MarkModeratorPosts']); 311 $newObjProp->update(); 312 313 $id = $this->getNewForumPk(); 314 $this->forum_obj_id = $newObjProp->getObjId(); 315 $this->mapping['frm'][$this->forumArray['Id']] = $id; 316 $this->lastHandledForumId = $id; 317 318 unset($this->forumArray); 319 } 320 321 break; 322 323 case 'Thread': 324 $update_str = "$this->lastHandledForumId#$this->lastHandledThreadId#$this->lastHandledPostId"; 325 $this->db->manipulateF( 326 "UPDATE frm_threads 327 SET thr_last_post = %s 328 WHERE thr_pk = %s", 329 array('text', 'integer'), 330 array($update_str, $this->lastHandledThreadId) 331 ); 332 break; 333 334 case 'Subject': 335 $x['Subject'] = $this->cdata; 336 break; 337 338 case 'Alias': 339 $x['Alias'] = $this->cdata; 340 break; 341 342 case 'Sticky': 343 $x['Sticky'] = $this->cdata; 344 break; 345 346 case 'Sorting': 347 $x['Sorting'] = $this->cdata; 348 break; 349 350 case 'MarkModeratorPosts': 351 $x['MarkModeratorPosts'] = $this->cdata; 352 break; 353 354 case 'Closed': 355 $x['Closed'] = $this->cdata; 356 357 if ($this->entity == 'thread' && $this->threadArray) { 358 $this->forumThread = new ilForumTopic(); 359 $this->forumThread->setId($this->threadArray['Id']); 360 $this->forumThread->setForumId($this->lastHandledForumId); 361 $this->forumThread->setSubject($this->threadArray['Subject']); 362 $this->forumThread->setSticky($this->threadArray['Sticky']); 363 $this->forumThread->setClosed($this->threadArray['Closed']); 364 $this->forumThread->setCreateDate($this->threadArray['CreateDate']); 365 $this->forumThread->setChangeDate($this->threadArray['UpdateDate']); 366 $this->forumThread->setImportName($this->threadArray['ImportName']); 367 368 $usr_data = $this->getUserIdAndAlias( 369 $this->threadArray['UserId'], 370 $this->threadArray['Alias'] 371 ); 372 373 $this->forumThread->setDisplayUserId($usr_data['usr_id']); 374 $this->forumThread->setUserAlias($usr_data['usr_alias']); 375 376 if (version_compare($this->getSchemaVersion(), '4.5.0', '<=')) { 377 $this->threadArray['AuthorId'] = $this->threadArray['UserId']; 378 } 379 380 $author_id_data = $this->getUserIdAndAlias( 381 $this->threadArray['AuthorId'] 382 ); 383 $this->forumThread->setThrAuthorId((int) $author_id_data['usr_id']); 384 385 $this->forumThread->insert(); 386 387 $this->mapping['thr'][$this->threadArray['Id']] = $this->forumThread->getId(); 388 $this->lastHandledThreadId = $this->forumThread->getId(); 389 390 unset($this->threadArray); 391 } 392 393 break; 394 395 case 'Post': 396 break; 397 398 case 'Censorship': 399 $x['Censorship'] = $this->cdata; 400 break; 401 402 case 'CensorshipMessage': 403 $x['CensorshipMessage'] = $this->cdata; 404 break; 405 406 case 'Notification': 407 $x['Notification'] = $this->cdata; 408 break; 409 410 case 'ImportName': 411 $x['ImportName'] = $this->cdata; 412 break; 413 414 case 'Status': 415 $x['Status'] = $this->cdata; 416 break; 417 418 case 'Message': 419 $x['Message'] = $this->cdata; 420 break; 421 422 case 'Lft': 423 $x['Lft'] = $this->cdata; 424 break; 425 426 case 'Rgt': 427 $x['Rgt'] = $this->cdata; 428 break; 429 430 case 'Depth': 431 $x['Depth'] = $this->cdata; 432 break; 433 434 case 'ParentId': 435 $x['ParentId'] = $this->cdata; 436 437 if ($this->entity == 'post' && $this->postArray) { 438 $this->forumPost = new ilForumPost(); 439 $this->forumPost->setId($this->postArray['Id']); 440 $this->forumPost->setCensorship($this->postArray['Censorship']); 441 $this->forumPost->setCensorshipComment($this->postArray['CensorshipMessage']); 442 $this->forumPost->setNotification($this->postArray['Notification']); 443 $this->forumPost->setImportName($this->postArray['ImportName']); 444 $this->forumPost->setStatus($this->postArray['Status']); 445 $this->forumPost->setMessage($this->postArray['Message']); 446 $this->forumPost->setSubject($this->postArray['Subject']); 447 $this->forumPost->setLft($this->postArray['Lft']); 448 $this->forumPost->setRgt($this->postArray['Rgt']); 449 $this->forumPost->setDepth($this->postArray['Depth']); 450 $this->forumPost->setParentId($this->postArray['ParentId']); 451 $this->forumPost->setThread($this->forumThread); 452 $this->forumPost->setThreadId($this->lastHandledThreadId); 453 $this->forumPost->setForumId($this->lastHandledForumId); 454 $this->forumPost->setCreateDate($this->postArray['CreateDate']); 455 $this->forumPost->setChangeDate($this->postArray['UpdateDate']); 456 457 $usr_data = $this->getUserIdAndAlias( 458 $this->postArray['UserId'], 459 $this->postArray['Alias'] 460 ); 461 $update_usr_data = $this->getUserIdAndAlias( 462 $this->postArray['UpdateUserId'] 463 ); 464 $this->forumPost->setDisplayUserId($usr_data['usr_id']); 465 $this->forumPost->setUserAlias($usr_data['usr_alias']); 466 $this->forumPost->setUpdateUserId($update_usr_data['usr_id']); 467 468 if (version_compare($this->getSchemaVersion(), '4.5.0', '<=')) { 469 $this->postArray['AuthorId'] = $this->postArray['UserId']; 470 } 471 $author_id_data = $this->getUserIdAndAlias( 472 $this->postArray['AuthorId'] 473 ); 474 $this->forumPost->setPosAuthorId((int) $author_id_data['usr_id']); 475 476 if ($this->postArray['isAuthorModerator'] === 'NULL') { 477 $this->forumPost->setIsAuthorModerator(null); 478 } else { 479 $this->forumPost->setIsAuthorModerator((int) $this->postArray['isAuthorModerator']); 480 } 481 482 $this->forumPost->insert(); 483 484 if ($this->mapping['pos'][$this->postArray['ParentId']]) { 485 $parentId = $this->mapping['pos'][$this->postArray['ParentId']]; 486 } else { 487 $parentId = 0; 488 } 489 490 $postTreeNodeId = $this->db->nextId('frm_posts_tree'); 491 $this->db->insert('frm_posts_tree', array( 492 'fpt_pk' => array('integer', $postTreeNodeId), 493 'thr_fk' => array('integer', $this->lastHandledThreadId), 494 'pos_fk' => array('integer', $this->forumPost->getId()), 495 'parent_pos' => array('integer', $parentId), 496 'lft' => array('integer', $this->postArray['Lft']), 497 'rgt' => array('integer', $this->postArray['Rgt']), 498 'depth' => array('integer', $this->postArray['Depth']), 499 'fpt_date' => array('timestamp', date('Y-m-d H:i:s')) 500 )); 501 502 $this->mapping['pos'][$this->postArray['Id']] = $this->forumPost->getId(); 503 $this->lastHandledPostId = $this->forumPost->getId(); 504 505 $media_objects_found = false; 506 foreach ($this->mediaObjects as $mob_attr) { 507 $importfile = $this->getImportDirectory() . '/' . $mob_attr['uri']; 508 if (file_exists($importfile)) { 509 $mob = ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false); 510 ilObjMediaObject::_saveUsage($mob->getId(), "frm:html", $this->forumPost->getId()); 511 512 $this->forumPost->setMessage( 513 str_replace( 514 array( 515 "src=\"" . $mob_attr["label"] . "\"", 516 "src=\"" . preg_replace("/(il)_[\d]+_(mob)_([\d]+)/", "$1_0_$2_$3", $mob_attr["label"]) . "\"" 517 ), 518 "src=\"" . "il_" . IL_INST_ID . "_mob_" . $mob->getId() . "\"", 519 $this->forumPost->getMessage() 520 ) 521 ); 522 $media_objects_found = true; 523 } 524 } 525 526 if ($media_objects_found) { 527 $this->forumPost->update(); 528 } 529 530 unset($this->postArray); 531 } 532 533 break; 534 535 case 'Content': 536 $x['content'] = $this->cdata; 537 break; 538 539 case 'Attachment': 540 $filedata = new ilFileDataForum($this->forum->getId(), $this->lastHandledPostId); 541 542 $importPath = $this->contentArray['content']; 543 544 if (strlen($importPath)) { 545 $importPath = $this->getImportDirectory() . '/' . $importPath; 546 547 $newFilename = preg_replace("/^\d+_\d+(_.*)/ims", $this->forum->getId() . "_" . $this->lastHandledPostId . "$1", basename($importPath)); 548 $path = $filedata->getForumPath(); 549 $newPath = $path . '/' . $newFilename; 550 @copy($importPath, $newPath); 551 } 552 break; 553 } 554 555 $this->cdata = ''; 556 557 return; 558 } 559 560 private function getIdAndAliasArray($imp_usr_id, $param = 'import') 561 { 562 $select = 'SELECT od.obj_id, ud.login 563 FROM object_data od 564 INNER JOIN usr_data ud 565 ON od.obj_id = ud.usr_id'; 566 567 if ($param == 'import') { 568 $where = ' WHERE od.import_id = ' . $this->db->quote( 569 'il_' . $this->import_install_id . '_usr_' . $imp_usr_id, 570 'text' 571 ); 572 } 573 574 if ($param == 'user') { 575 $where = ' WHERE ud.usr_id = ' . $this->db->quote( 576 $imp_usr_id, 577 'integer' 578 ); 579 } 580 581 $query = $this->db->query($select . $where); 582 583 while ($res = $this->db->fetchAssoc($query)) { 584 break; 585 } 586 587 if ($res) { 588 return array( 589 'usr_id' => $res['obj_id'], 590 'usr_alias' => $res['login'] 591 ); 592 } else { 593 return false; 594 } 595 } 596 597 private function getAnonymousArray() 598 { 599 return array( 600 'usr_id' => $this->aobject->getId(), 601 'usr_alias' => $this->aobject->getLogin() 602 ); 603 } 604 605 606 private function getUserIdAndAlias($imp_usr_id, $imp_usr_alias = '') 607 { 608 if ((int) $imp_usr_id > 0) { 609 $newUsrId = -1; 610 611 if ($this->import_install_id != IL_INST_ID && IL_INST_ID > 0) { 612 // Different installations 613 if ($this->user_id_mapping[$imp_usr_id]) { 614 return $this->user_id_mapping[$imp_usr_id]; 615 } else { 616 $res = $this->getIdAndAliasArray($imp_usr_id, 'import'); 617 618 if ($res) { 619 $this->user_id_mapping[$imp_usr_id] = $res; 620 621 return $res; 622 } else { 623 $return_value = $this->getAnonymousArray(); 624 $this->user_id_mapping[$imp_usr_id] = $return_value; 625 626 return $return_value; 627 } 628 } 629 } elseif ($this->import_install_id == IL_INST_ID && IL_INST_ID == 0) { 630 // Eventually different installations. We cannot determine it. 631 if ($this->user_id_mapping[$imp_usr_id]) { 632 return $this->user_id_mapping[$imp_usr_id]; 633 } else { 634 $res = $this->getIdAndAliasArray($imp_usr_id, 'import'); 635 636 if ($res) { 637 $this->user_id_mapping[$imp_usr_id] = $res; 638 639 return $res; 640 } else { 641 // Same installation 642 if ($this->user_id_mapping[$imp_usr_id]) { 643 return $this->user_id_mapping[$imp_usr_id]; 644 } else { 645 $res = $this->getIdAndAliasArray($imp_usr_id, 'user'); 646 647 if ($res) { 648 $this->user_id_mapping[$imp_usr_id] = $res; 649 650 return $res; 651 } else { 652 $return_value = $this->getAnonymousArray(); 653 $this->user_id_mapping[$imp_usr_id] = $return_value; 654 655 return $return_value; 656 } 657 } 658 } 659 } 660 } else { 661 // Same installation 662 if ($this->user_id_mapping[$imp_usr_id]) { 663 return $this->user_id_mapping[$imp_usr_id]; 664 } else { 665 $res = $this->getIdAndAliasArray($imp_usr_id, 'user'); 666 667 if ($res) { 668 $this->user_id_mapping[$imp_usr_id] = $res; 669 670 return $res; 671 } else { 672 $return_value = $this->getAnonymousArray(); 673 $this->user_id_mapping[$imp_usr_id] = $return_value; 674 675 return $return_value; 676 } 677 } 678 } 679 } else { 680 return array( 681 'usr_id' => $imp_usr_id, 682 'usr_alias' => $imp_usr_alias 683 ); 684 } 685 } 686 687 public function setImportInstallId($id) 688 { 689 $this->import_install_id = $id; 690 } 691 692 private function getNewForumPk() 693 { 694 $query = "SELECT top_pk FROM frm_data 695 WHERE top_frm_fk = " . $this->db->quote( 696 $this->forum->getId(), 697 'integer' 698 ); 699 $res = $this->db->query($query); 700 $data = $this->db->fetchAssoc($res); 701 702 return $data['top_pk']; 703 } 704 705 /** 706 * handler for character data 707 * 708 * @param resource $a_xml_parser xml parser 709 * @param string $a_data character data 710 */ 711 public function handlerCharacterData($a_xml_parser, $a_data) 712 { 713 if ($a_data != "\n") { 714 // Replace multiple tabs with one space 715 $a_data = preg_replace("/\t+/", " ", $a_data); 716 717 $this->cdata .= $a_data; 718 } 719 } 720 721 /** 722 * starts parsing an changes object by side effect. 723 * 724 * @return boolean true, if no errors happend. 725 * 726 */ 727 public function start() 728 { 729 $this->startParsing(); 730 return $this->result > 0; 731 } 732} 733