• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

classes/class.ilValidator.php

Go to the documentation of this file.
00001 <?php
00002 /*
00003         +-----------------------------------------------------------------------------+
00004         | ILIAS open source                                                           |
00005         +-----------------------------------------------------------------------------+
00006         | Copyright (c) 1998-2001 ILIAS open source, University of Cologne            |
00007         |                                                                             |
00008         | This program is free software; you can redistribute it and/or               |
00009         | modify it under the terms of the GNU General Public License                 |
00010         | as published by the Free Software Foundation; either version 2              |
00011         | of the License, or (at your option) any later version.                      |
00012         |                                                                             |
00013         | This program is distributed in the hope that it will be useful,             |
00014         | but WITHOUT ANY WARRANTY; without even the implied warranty of              |
00015         | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
00016         | GNU General Public License for more details.                                |
00017         |                                                                             |
00018         | You should have received a copy of the GNU General Public License           |
00019         | along with this program; if not, write to the Free Software                 |
00020         | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. |
00021         +-----------------------------------------------------------------------------+
00022 */
00023 
00032 class ilValidator extends PEAR
00033 {
00038         var $rbac_object_types = NULL;
00039 
00044         // i added folder due to bug #1860 (even if this will not completely fix it)
00045         // and the fact, that media pool folders may find their way into
00046         // the recovery folder (what results in broken pools, if the are deleted)
00047         // Alex, 2006-07-21
00048         var $object_types_exclude = array("adm","root","mail","usrf","objf","lngf",
00049                 "trac","taxf","auth","rolf","file","assf","extt","adve","fold");
00050         
00055         var $mode = array(
00056                                                 "scan"                  => true,                // gather information about corrupted entries
00057                                                 "dump_tree"             => false,               // dump tree
00058                                                 "clean"                 => false,               // remove all unusable entries & renumber tree
00059                                                 "restore"               => false,               // restore objects with invalid parent to RecoveryFolder
00060                                                 "purge"                 => false,               // delete all objects with invalid parent from system
00061                                                 "restore_trash" => false,               // restore all objects in trash to RecoveryFolder
00062                                                 "purge_trash"   => false                // delete all objects in trash from system
00063                                         );
00064 
00069         var $invalid_references = array();
00070 
00075         var $invalid_childs = array();
00076 
00081         var $missing_objects = array();
00082 
00087         var $unbound_objects = array();
00088 
00093         var $deleted_objects = array();
00094 
00101         var $invalid_rolefolders = array();
00102         
00107         var $invalid_objects = array();
00108         
00113         var $logging = false;
00114         
00119         var $scan_log;
00120         
00121         var $scan_log_file = "scanlog.log";
00122         
00123         var $scan_log_separator = "<!-- scan log start -->";
00124 
00131         function ilValidator($a_log = false)
00132         {
00133                 global $objDefinition, $ilDB;
00134                 
00135                 $this->PEAR();
00136                 $this->db =& $ilDB;
00137                 $this->rbac_object_types = "'".implode("','",$objDefinition->getAllRBACObjects())."'";
00138         $this->setErrorHandling(PEAR_ERROR_CALLBACK,array(&$this, 'handleErr'));
00139                 
00140                 if ($a_log === true)
00141                 {
00142                         $this->logging = true;
00143 
00144                         // should be available thru inc.header.php
00145                         // TODO: move log functionality to new class ilScanLog
00146                         include_once "classes/class.ilLog.php";
00147                 
00148                         // create scan log
00149                         $this->scan_log = new ilLog(CLIENT_DATA_DIR,"scanlog.log");
00150                         $this->scan_log->setLogFormat("");
00151                         $this->writeScanLogLine($this->scan_log_separator);
00152                         $this->writeScanLogLine("\n[Systemscan from ".date("y-m-d H:i]"));
00153                 }
00154         }
00155 
00167         function setMode($a_mode,$a_value)
00168         {
00169                 if ((!in_array($a_mode,array_keys($this->mode)) and $a_mode != "all") or !is_bool($a_value))
00170                 {
00171                         $this->throwError(INVALID_PARAM, FATAL, DEBUG);
00172                         return false;
00173                 }
00174                 
00175                 if ($a_mode == "all")
00176                 {
00177                         foreach ($this->mode as $mode => $value)
00178                         {
00179                                 $this->mode[$mode] = $a_value;
00180                         }
00181                 }
00182                 else
00183                 {
00184                         $this->mode[$a_mode] = $a_value;
00185                 }
00186                 
00187                 // consider mode dependencies
00188                 $this->setModeDependencies();
00189 
00190                 return true;
00191         }
00192         
00201         function isModeEnabled($a_mode)
00202         {
00203                 if (!in_array($a_mode,array_keys($this->mode)))
00204                 {
00205                         $this->throwError(VALIDATER_UNKNOWN_MODE, WARNING, DEBUG);
00206                         return false;
00207                 }
00208                 
00209                 return $this->mode[$a_mode];
00210         }
00211         
00212         function isLogEnabled()
00213         {
00214                 return $this->logging;
00215         }
00216         
00225         function setModeDependencies()
00226         {
00227                 // DO NOT change the order
00228                 
00229                 if ($this->mode["restore"] === true)
00230                 {
00231                         $this->mode["scan"] = true;
00232                         $this->mode["purge"] = false;
00233                 }
00234 
00235                 if ($this->mode["purge"] === true)
00236                 {
00237                         $this->mode["scan"] = true;
00238                         $this->mode["restore"] = false;
00239                 }
00240 
00241                 if ($this->mode["restore_trash"] === true)
00242                 {
00243                         $this->mode["scan"] = true;
00244                         $this->mode["purge_trash"] = false;
00245                 }
00246 
00247                 if ($this->mode["purge_trash"] === true)
00248                 {
00249                         $this->mode["scan"] = true;
00250                         $this->mode["restore_trash"] = false;
00251                 }
00252 
00253                 if ($this->mode["clean"] === true)
00254                 {
00255                         $this->mode["scan"] = true;
00256                 }
00257         }
00258 
00267         function validate()
00268         {
00269                 global $lng;
00270                 
00271                 // The validation summary.
00272                 $summary = "";
00273 
00274 
00275                 // STEP 1: Scan
00276                 // -------------------
00277                 $summary .= $lng->txt("scanning_system");
00278                 if (!$this->isModeEnabled("scan"))
00279                 {
00280                         $summary .= $lng->txt("disabled");
00281                 }
00282                 else
00283                 {
00284                         $summary .= "<br/>".$lng->txt("searching_invalid_refs");
00285                         if ($this->findInvalidReferences())
00286                         {
00287                                 $summary .= count($this->getInvalidReferences())." ".$lng->txt("found");
00288                         }
00289                         else
00290                         {
00291                                 $summary .= $lng->txt("found_none");
00292                         }
00293                         
00294                         $summary .= "<br/>".$lng->txt("searching_invalid_childs");
00295                         if ($this->findInvalidChilds())
00296                         {
00297                                 $summary .= count($this->getInvalidChilds())." ".$lng->txt("found");
00298 
00299                         }
00300                         else
00301                         {
00302                                 $summary .= $lng->txt("found_none");
00303                         }
00304                         
00305                         $summary .= "<br/>".$lng->txt("searching_missing_objs");
00306                         if ($this->findMissingObjects())
00307                         {
00308                                 $summary .= count($this->getMissingObjects())." ".$lng->txt("found");
00309 
00310                         }
00311                         else
00312                         {
00313                                 $summary .= $lng->txt("found_none");
00314                         }
00315                 
00316                         $summary .= "<br/>".$lng->txt("searching_unbound_objs");
00317                         if ($this->findUnboundObjects())
00318                         {
00319                                 $summary .=  count($this->getUnboundObjects())." ".$lng->txt("found");
00320 
00321                         }
00322                         else
00323                         {
00324                                 $summary .= $lng->txt("found_none");
00325                         }
00326                 
00327                         $summary .= "<br/>".$lng->txt("searching_deleted_objs");
00328                         if ($this->findDeletedObjects())
00329                         {
00330                                 $summary .= count($this->getDeletedObjects())." ".$lng->txt("found");
00331 
00332                         }
00333                         else
00334                         {
00335                                 $summary .= $lng->txt("found_none");
00336                         }
00337 
00338                         $summary .= "<br/>".$lng->txt("searching_invalid_rolfs");
00339                         if ($this->findInvalidRolefolders())
00340                         {
00341                                 $summary .= count($this->getInvalidRolefolders())." ".$lng->txt("found");
00342 
00343                         }
00344                         else
00345                         {
00346                                 $summary .= $lng->txt("found_none");
00347                         }
00348                         
00349                         $summary .= "<br/><br/>".$lng->txt("analyzing_tree_structure");
00350                         if ($this->checkTreeStructure())
00351                         {
00352                                 $summary .= $lng->txt("tree_corrupt");
00353                         }
00354                         else
00355                         {
00356                                 $summary .= $lng->txt("disabled");
00357                         }
00358                 }
00359                 
00360                 // STEP 2: Dump tree
00361                 // -------------------
00362                 $summary .= "<br /><br />".$lng->txt("dumping_tree");
00363                 if (!$this->isModeEnabled("dump_tree"))
00364                 {
00365                         $summary .= $lng->txt("disabled");
00366                 }
00367                 else
00368                 {
00369                         $error_count = $this->dumpTree();
00370                         if ($error_count > 0)
00371                         {
00372                                 $summary .= $lng->txt("tree_corrupt");
00373                         }
00374                         else
00375                         {
00376                                 $summary .= $lng->txt("done");
00377                         }
00378                 }
00379 
00380                 // STEP 3: Clean Up
00381                 // -------------------
00382                 $summary .= "<br /><br />".$lng->txt("cleaning");
00383                 if (!$this->isModeEnabled("clean"))
00384                 {
00385                         $summary .= $lng->txt("disabled");
00386                 }
00387                 else
00388                 {
00389                         $summary .= "<br />".$lng->txt("removing_invalid_refs");
00390                         if ($this->removeInvalidReferences())
00391                         {
00392                                 $summary .= strtolower($lng->txt("done"));
00393                         }
00394                         else
00395                         {
00396                                 $summary .= $lng->txt("nothing_to_remove").$lng->txt("skipped");
00397                         }
00398                         
00399                         $summary .= "<br />".$lng->txt("removing_invalid_childs");
00400                         if ($this->removeInvalidChilds())
00401                         {
00402                                 $summary .= strtolower($lng->txt("done"));
00403                         }
00404                         else
00405                         {
00406                                 $summary .= $lng->txt("nothing_to_remove").$lng->txt("skipped");
00407                         }
00408 
00409                         $summary .= "<br />".$lng->txt("removing_invalid_rolfs");
00410                         if ($this->removeInvalidRolefolders())
00411                         {
00412                                 $summary .= strtolower($lng->txt("done"));
00413                         }
00414                         else
00415                         {
00416                                 $summary .= $lng->txt("nothing_to_remove").$lng->txt("skipped");
00417                         }
00418 
00419                         // find unbound objects again AFTER cleaning process!
00420                         // This updates the array 'unboundobjects' required for the further steps
00421                         // There might be other objects unbounded now due to removal of object_data/reference entries.
00422                         $this->findUnboundObjects();
00423                 }
00424 
00425                 // STEP 4: Restore objects
00426                 $summary .= "<br /><br />".$lng->txt("restoring");
00427                 
00428                 if (!$this->isModeEnabled("restore"))
00429                 {
00430                         $summary .= $lng->txt("disabled");
00431                 }
00432                 else
00433                 {
00434                         $summary .= "<br />".$lng->txt("restoring_missing_objs");
00435                         if ($this->restoreMissingObjects())
00436                         {
00437                                 $summary .= strtolower($lng->txt("done"));
00438                         }
00439                         else
00440                         {
00441                                 $summary .= $lng->txt("nothing_to_restore").$lng->txt("skipped");
00442                         }
00443                         
00444                         $summary .= "<br />".$lng->txt("restoring_unbound_objs");
00445                         if ($this->restoreUnboundObjects())
00446                         {
00447                                 $summary .= strtolower($lng->txt("done"));
00448                         }
00449                         else
00450                         {
00451                                 $summary .= $lng->txt("nothing_to_restore").$lng->txt("skipped");
00452                         }
00453                 }
00454                 
00455                 // STEP 5: Restoring Trash
00456                 $summary .= "<br /><br />".$lng->txt("restoring_trash");
00457 
00458                 if (!$this->isModeEnabled("restore_trash"))
00459                 {
00460                         $summary .= $lng->txt("disabled");
00461                 }
00462                 else
00463                 {
00464                         if ($this->restoreTrash())
00465                         {
00466                                 $summary .= strtolower($lng->txt("done"));
00467                         }
00468                         else
00469                         {
00470                                 $summary .= $lng->txt("nothing_to_restore").$lng->txt("skipped");
00471                         }
00472                 }
00473                 
00474                 // STEP 6: Purging...
00475                 $summary .= "<br /><br />".$lng->txt("purging");
00476                 
00477                 if (!$this->isModeEnabled("purge"))
00478                 {
00479                         $summary .= $lng->txt("disabled");
00480                 }
00481                 else
00482                 {
00483                         $summary .= "<br />".$lng->txt("purging_missing_objs");
00484                         if ($this->purgeMissingObjects())
00485                         {
00486                                 $summary .= strtolower($lng->txt("done"));
00487                         }
00488                         else
00489                         {
00490                                 $summary .= $lng->txt("nothing_to_purge").$lng->txt("skipped");
00491                         }
00492 
00493                         $summary .= "<br />".$lng->txt("purging_unbound_objs");
00494                         if ($this->purgeUnboundObjects())
00495                         {
00496                                 $summary .= strtolower($lng->txt("done"));
00497                         }
00498                         else
00499                         {
00500                                 $summary .= $lng->txt("nothing_to_purge").$lng->txt("skipped");
00501                         }
00502                 }
00503 
00504                 // STEP 7: Purging trash...
00505                 $summary .= "<br /><br />".$lng->txt("purging_trash");
00506                 
00507                 if (!$this->isModeEnabled("purge_trash"))
00508                 {
00509                         $summary .= $lng->txt("disabled");
00510                 }
00511                 else
00512                 {
00513                         if ($this->purgeTrash())
00514                         {
00515                                 $summary .= strtolower($lng->txt("done"));
00516                         }
00517                         else
00518                         {
00519                                 $summary .= $lng->txt("nothing_to_purge").$lng->txt("skipped");
00520                         }
00521                 }
00522                 
00523                 // STEP 8: Initialize gaps in tree
00524                 if ($this->isModeEnabled("clean"))
00525                 {
00526                         $summary .= "<br /><br />".$lng->txt("cleaning_final");
00527                         if ($this->initGapsInTree())
00528                         {
00529                                 $summary .= "<br />".$lng->txt("initializing_gaps")." ".strtolower($lng->txt("done"));
00530                         }
00531                 }
00532                 
00533                 // check RBAC starts here
00534                 // ...
00535                 
00536                 // le fin
00537                 foreach ($this->mode as $mode => $value)
00538                 {
00539                         $arr[] = $mode."[".(int)$value."]";
00540                 }
00541                 
00542                 return $summary;
00543         }
00544 
00545 
00555         function findMissingObjects()
00556         {
00557                 // check mode: analyze
00558                 if ($this->mode["scan"] !== true)
00559                 {
00560                         return false;
00561                 }
00562                 
00563                 // init
00564                 $this->missing_objects = array();
00565         
00566                 $this->writeScanLogLine("\nfindMissingObjects:");
00567                 
00568                 $q = "SELECT object_data.*, ref_id FROM object_data ".
00569                          "LEFT JOIN object_reference ON object_data.obj_id = object_reference.obj_id ".
00570                          "LEFT JOIN tree ON object_reference.ref_id = tree.child ".
00571                          "WHERE (object_reference.obj_id IS NULL OR tree.child IS NULL) ".
00572                          "AND object_data.type IN (".$this->rbac_object_types.")";
00573                 $r = $this->db->query($q);
00574                 
00575                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00576                 {
00577                         if (!in_array($row->type,$this->object_types_exclude))
00578                         {
00579                                 $this->missing_objects[] = array(
00580                                                                                                         "obj_id"                => $row->obj_id,
00581                                                                                                         "type"                  => $row->type,
00582                                                                                                         "ref_id"                => $row->ref_id,
00583                                                                                                         "child"                 => $row->child,
00584                                                                                                         "title"                 => $row->title,
00585                                                                                                         "desc"                  => $row->description,
00586                                                                                                         "owner"                 => $row->owner,
00587                                                                                                         "create_date"   => $row->create_date,
00588                                                                                                         "last_update"   => $row->last_update
00589                                                                                                 );
00590                         }
00591                 }
00592                 
00593                 if (count($this->missing_objects) > 0)
00594                 {
00595                         $this->writeScanLogLine("obj_id\ttype\tref_id\tchild\ttitle\tdesc\towner\tcreate_date\tlast_update");
00596                         $this->writeScanLogArray($this->missing_objects);
00597                         return true;
00598                 }
00599 
00600                 $this->writeScanLogLine("none");
00601                 return false;   
00602         }
00603 
00615         function findInvalidRolefolders()
00616         {
00617                 // check mode: analyze
00618                 if ($this->mode["scan"] !== true)
00619                 {
00620                         return false;
00621                 }
00622                 
00623                 // init
00624                 $this->invalid_rolefolders = array();
00625                 
00626                 $this->writeScanLogLine("\nfindInvalidRolefolders:");
00627 
00628                 // find rolfs without reference/tree entry
00629                 $q = "SELECT object_data.*, ref_id FROM object_data ".
00630                          "LEFT JOIN object_reference ON object_data.obj_id = object_reference.obj_id ".
00631                          "LEFT JOIN tree ON object_reference.ref_id = tree.child ".
00632                          "WHERE (object_reference.obj_id IS NULL OR tree.child IS NULL) ".
00633                          "AND object_data.type='rolf'";
00634                 $r = $this->db->query($q);
00635                 
00636                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00637                 {
00638                         $this->invalid_rolefolders[] = array(
00639                                                                                                 "obj_id"                => $row->obj_id,
00640                                                                                                 "type"                  => $row->type,
00641                                                                                                 "ref_id"                => $row->ref_id,
00642                                                                                                 "child"                 => $row->child,
00643                                                                                                 "title"                 => $row->title,
00644                                                                                                 "desc"                  => $row->description,
00645                                                                                                 "owner"                 => $row->owner,
00646                                                                                                 "create_date"   => $row->create_date,
00647                                                                                                 "last_update"   => $row->last_update
00648                                                                                         );
00649                 }
00650                 
00651                 // find rolfs within RECOVERY FOLDER
00652                 $q = "SELECT object_data.*, ref_id FROM object_data ".
00653                          "LEFT JOIN object_reference ON object_data.obj_id = object_reference.obj_id ".
00654                          "LEFT JOIN tree ON object_reference.ref_id = tree.child ".
00655                          "WHERE object_reference.ref_id ='".RECOVERY_FOLDER_ID."' ".
00656                          "AND object_data.type='rolf'";
00657                 $r = $this->db->query($q);
00658                 
00659                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00660                 {
00661                         $this->invalid_rolefolders[] = array(
00662                                                                                                 "obj_id"                => $row->obj_id,
00663                                                                                                 "type"                  => $row->type,
00664                                                                                                 "ref_id"                => $row->ref_id,
00665                                                                                                 "child"                 => $row->child,
00666                                                                                                 "title"                 => $row->title,
00667                                                                                                 "desc"                  => $row->description,
00668                                                                                                 "owner"                 => $row->owner,
00669                                                                                                 "create_date"   => $row->create_date,
00670                                                                                                 "last_update"   => $row->last_update
00671                                                                                         );
00672                 }
00673                         
00674                 if (count($this->invalid_rolefolders) > 0)
00675                 {
00676                         $this->writeScanLogLine("obj_id\ttype\tref_id\tchild\ttitle\tdesc\towner\tcreate_date\tlast_update");
00677                         $this->writeScanLogArray($this->invalid_rolefolders);
00678                         return true;
00679                 }
00680 
00681                 $this->writeScanLogLine("none");
00682                 return false;   
00683         }
00684 
00694         function findInvalidRBACEntries()
00695         {
00696                 // check mode: analyze
00697                 if ($this->mode["scan"] !== true)
00698                 {
00699                         return false;
00700                 }
00701                 
00702                 // init
00703                 $this->invalid_rbac_entries = array();
00704                 
00705                 $this->writeScanLogLine("\nfindInvalidRBACEntries:");
00706 
00707                 $q = "SELECT object_data.*, ref_id FROM object_data ".
00708                          "LEFT JOIN object_reference ON object_data.obj_id = object_reference.obj_id ".
00709                          "LEFT JOIN tree ON object_reference.ref_id = tree.child ".
00710                          "WHERE (object_reference.obj_id IS NULL OR tree.child IS NULL) ".
00711                          "AND object_data.type='rolf'";
00712                 $r = $this->db->query($q);
00713                 
00714                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00715                 {
00716                         $this->invalid_rolefolders[] = array(
00717                                                                                                 "obj_id"                => $row->obj_id,
00718                                                                                                 "type"                  => $row->type,
00719                                                                                                 "ref_id"                => $row->ref_id,
00720                                                                                                 "child"                 => $row->child,
00721                                                                                                 "title"                 => $row->title,
00722                                                                                                 "desc"                  => $row->description,
00723                                                                                                 "owner"                 => $row->owner,
00724                                                                                                 "create_date"   => $row->create_date,
00725                                                                                                 "last_update"   => $row->last_update
00726                                                                                         );
00727                 }
00728                 
00729                 // find rolfs within RECOVERY FOLDER
00730                 $q = "SELECT object_data.*, ref_id FROM object_data ".
00731                          "LEFT JOIN object_reference ON object_data.obj_id = object_reference.obj_id ".
00732                          "LEFT JOIN tree ON object_reference.ref_id = tree.child ".
00733                          "WHERE object_reference.ref_id ='".RECOVERY_FOLDER_ID."' ".
00734                          "AND object_data.type='rolf'";
00735                 $r = $this->db->query($q);
00736                 
00737                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00738                 {
00739                         $this->invalid_rolefolders[] = array(
00740                                                                                                 "obj_id"                => $row->obj_id,
00741                                                                                                 "type"                  => $row->type,
00742                                                                                                 "ref_id"                => $row->ref_id,
00743                                                                                                 "child"                 => $row->child,
00744                                                                                                 "title"                 => $row->title,
00745                                                                                                 "desc"                  => $row->description,
00746                                                                                                 "owner"                 => $row->owner,
00747                                                                                                 "create_date"   => $row->create_date,
00748                                                                                                 "last_update"   => $row->last_update
00749                                                                                         );
00750                 }
00751                         
00752                 if (count($this->invalid_rolefolders) > 0)
00753                 {
00754                         $this->writeScanLogLine("obj_id\ttype\tref_id\tchild\ttitle\tdesc\towner\tcreate_date\tlast_update");
00755                         $this->writeScanLogArray($this->invalid_rolefolders);
00756                         return true;
00757                 }
00758 
00759                 $this->writeScanLogLine("none");
00760                 return false;   
00761         }
00762 
00776         function getMissingObjects()
00777         {
00778                 return $this->missing_objects;
00779         }
00780 
00790         function findInvalidReferences()
00791         {
00792                 // check mode: analyze
00793                 if ($this->mode["scan"] !== true)
00794                 {
00795                         return false;
00796                 }
00797 
00798                 // init
00799                 $this->invalid_references = array();
00800                 
00801                 $this->writeScanLogLine("\nfindInvalidReferences:");
00802 
00803                 $q = "SELECT object_reference.* FROM object_reference ".
00804                          "LEFT JOIN object_data ON object_data.obj_id = object_reference.obj_id ".
00805                          "WHERE object_data.obj_id IS NULL ".
00806                          "OR object_data.type NOT IN (".$this->rbac_object_types.")";
00807                 $r = $this->db->query($q);
00808                 
00809                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00810                 {
00811                         $this->invalid_references[] = array(
00812                                                                                         "ref_id"        => $row->ref_id,
00813                                                                                         "obj_id"        => $row->obj_id,
00814                                                                                         "msg"           => "Object does not exist."
00815                                                                                         );
00816                 }
00817 
00818                 if (count($this->invalid_references) > 0)
00819                 {
00820                         $this->writeScanLogLine("ref_id\t\tobj_id");
00821                         $this->writeScanLogArray($this->invalid_references);
00822                         return true;
00823                 }
00824 
00825                 $this->writeScanLogLine("none");
00826                 return false;   
00827         }
00828 
00837         function getInvalidReferences()
00838         {
00839                 return $this->invalid_references;
00840         }
00841 
00851         function findInvalidChilds()
00852         {
00853                 // check mode: analyze
00854                 if ($this->mode["scan"] !== true)
00855                 {
00856                         return false;
00857                 }
00858 
00859                 // init
00860                 $this->invalid_childs = array();
00861 
00862                 $this->writeScanLogLine("\nfindInvalidChilds:");
00863 
00864                 $q = "SELECT tree.*,object_reference.ref_id FROM tree ".
00865                          "LEFT JOIN object_reference ON tree.child = object_reference.ref_id ".
00866                          "LEFT JOIN object_data ON object_reference.obj_id = object_data.obj_id ".
00867                          "WHERE object_reference.ref_id IS NULL or object_data.obj_id IS NULL";
00868                 $r = $this->db->query($q);
00869                 
00870                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00871                 {
00872                         $this->invalid_childs[] = array(
00873                                                                                         "child"         => $row->child,
00874                                                                                         "ref_id"        => $row->ref_id,
00875                                                                                         "msg"           => "No object found"
00876                                                                                         );
00877                 }
00878 
00879                 if (count($this->invalid_childs) > 0)
00880                 {
00881                         $this->writeScanLogLine("child\t\tref_id");
00882                         $this->writeScanLogArray($this->invalid_childs);
00883                         return true;
00884                 }
00885 
00886                 $this->writeScanLogLine("none");
00887                 return false;
00888         }
00889 
00898         function getInvalidChilds()
00899         {
00900                 return $this->invalid_childs;
00901         }
00902 
00914         function findUnboundObjects()
00915         {
00916                 // check mode: analyze
00917                 if ($this->mode["scan"] !== true)
00918                 {
00919                         return false;
00920                 }
00921 
00922                 // init
00923                 $this->unbound_objects = array();
00924 
00925                 $this->writeScanLogLine("\nfindUnboundObjects:");
00926 
00927                 $q = "SELECT T2.tree AS deleted,T1.child,T1.parent,T2.parent AS grandparent FROM tree AS T1 ".
00928                          "LEFT JOIN tree AS T2 ON T2.child=T1.parent ".
00929                          "WHERE (T2.tree!=1 OR T2.tree IS NULL) AND T1.parent!=0";
00930                 $r = $this->db->query($q);
00931                 
00932                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00933                 {
00934                         // exclude deleted nodes
00935                         if ($row->deleted === NULL)
00936                         {
00937                                 $this->unbound_objects[] = array(
00938                                                                                                 "child"                 => $row->child,
00939                                                                                                 "parent"                => $row->parent,
00940                                                                                                 "tree"                  => 1,
00941                                                                                                 "msg"                   => "No valid parent node found"
00942                                                                                                 );
00943                         }
00944                 }
00945 
00946                 if (count($this->unbound_objects) > 0)
00947                 {
00948                         $this->writeScanLogLine("child\t\tparent\ttree");
00949                         $this->writeScanLogArray($this->unbound_objects);
00950                         return true;
00951                 }
00952 
00953                 $this->writeScanLogLine("none");
00954                 return false;
00955         }
00956 
00968         function findDeletedObjects()
00969         {
00970                 // check mode: analyze
00971                 if ($this->mode["scan"] !== true)
00972                 {
00973                         return false;
00974                 }
00975 
00976                 // init
00977                 $this->deleted_objects = array();
00978 
00979                 $this->writeScanLogLine("\nfindDeletedObjects:");
00980 
00981                 $q = "SELECT object_data.*,tree.tree,tree.child,tree.parent FROM object_data ".
00982                          "LEFT JOIN object_reference ON object_data.obj_id=object_reference.obj_id ".
00983                          "LEFT JOIN tree ON tree.child=object_reference.ref_id ".
00984                          " WHERE tree !=1";
00985                 $r = $this->db->query($q);
00986                 
00987                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00988                 {
00989                         $this->deleted_objects[] = array(
00990                                                                                         "child"                 => $row->child,
00991                                                                                         "parent"                => $row->parent,
00992                                                                                         "tree"                  => $row->tree,
00993                                                                                         "type"                  => $row->type,
00994                                                                                         "title"                 => $row->title,
00995                                                                                         "desc"                  => $row->description,
00996                                                                                         "owner"                 => $row->owner,
00997                                                                                         "create_date"   => $row->create_date,
00998                                                                                         "last_update"   => $row->last_update
00999                                                                                         );
01000                 }
01001 
01002                 if (count($this->deleted_objects) > 0)
01003                 {
01004                         $this->writeScanLogLine("obj_id\tref_id\ttree\ttype\ttitle\tdesc\towner\tcreate_date\tlast_update");
01005                         $this->writeScanLogArray($this->deleted_objects);
01006                         return true;
01007                 }
01008 
01009                 $this->writeScanLogLine("none");
01010                 return false;
01011         }
01012         
01013 
01027         function getUnboundObjects()
01028         {
01029                 return $this->unbound_objects;
01030         }
01031 
01038         function getDeletedObjects()
01039         {
01040                 return $this->deleted_objects;
01041         }
01042         
01051         function getInvalidRolefolders()
01052         {
01053                 return $this->invalid_rolefolders;
01054         }
01055 
01065         function removeInvalidReferences($a_invalid_refs = NULL)
01066         {
01067                 global $ilLog;
01068 
01069                 // check mode: clean
01070                 if ($this->mode["clean"] !== true)
01071                 {
01072                         return false;
01073                 }
01074 
01075                 $this->writeScanLogLine("\nremoveInvalidReferences:");
01076 
01077                 if ($a_invalid_refs === NULL and isset($this->invalid_references))
01078                 {
01079                         $a_invalid_refs =& $this->invalid_references; 
01080                 }
01081 
01082                 // handle wrong input
01083                 if (!is_array($a_invalid_refs))
01084                 {
01085                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01086                         return false;
01087                 }
01088                 // no unbound references found. do nothing
01089                 if (count($a_invalid_refs) == 0)
01090                 {
01091                         $this->writeScanLogLine("none");
01092                         return false;
01093                 }
01094 
01095 /*******************
01096 removal starts here
01097 ********************/
01098 
01099                 $message = sprintf('%s::removeInvalidReferences(): Started...',
01100                                                    get_class($this));
01101                 $ilLog->write($message,$ilLog->WARNING);
01102 
01103                 foreach ($a_invalid_refs as $entry)
01104                 {
01105                         $q = "DELETE FROM object_reference WHERE ref_id='".$entry["ref_id"]."' AND obj_id='".$entry["obj_id"]."'";
01106                         $this->db->query($q);
01107 
01108                         $message = sprintf('%s::removeInvalidReferences(): Reference %s removed',
01109                                                            get_class($this),
01110                                                            $entry["ref_id"]);
01111                         $ilLog->write($message,$ilLog->WARNING);
01112                         
01113                         $this->writeScanLogLine("Entry ".$entry["ref_id"]." removed");
01114                 }
01115                 
01116                 return true;    
01117         }
01118 
01128         function removeInvalidChilds($a_invalid_childs = NULL)
01129         {
01130                 global $ilLog;
01131 
01132                 // check mode: clean
01133                 if ($this->mode["clean"] !== true)
01134                 {
01135                         return false;
01136                 }
01137 
01138                 $this->writeScanLogLine("\nremoveInvalidChilds:");
01139 
01140                 if ($a_invalid_childs === NULL and isset($this->invalid_childs))
01141                 {
01142                         $a_invalid_childs =& $this->invalid_childs; 
01143                 }
01144 
01145                 // handle wrong input
01146                 if (!is_array($a_invalid_childs))
01147                 {
01148                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01149                         return false;
01150                 }
01151 
01152                 // no unbound childs found. do nothing
01153                 if (count($a_invalid_childs) == 0)
01154                 {
01155                         $this->writeScanLogLine("none");
01156                         return false;
01157                 }
01158 
01159 /*******************
01160 removal starts here
01161 ********************/
01162 
01163                 $message = sprintf('%s::removeInvalidChilds(): Started...',
01164                                                    get_class($this));
01165                 $ilLog->write($message,$ilLog->WARNING);
01166 
01167                 foreach ($a_invalid_childs as $entry)
01168                 {
01169                         $q = "DELETE FROM tree WHERE child='".$entry["child"]."'";
01170                         $this->db->query($q);
01171 
01172                         $message = sprintf('%s::removeInvalidChilds(): Entry child=%s removed',
01173                                                            get_class($this),
01174                                                            $entry["child"]);
01175                         $ilLog->write($message,$ilLog->WARNING);
01176                                 
01177                         $this->writeScanLogLine("Entry ".$entry["child"]." removed");
01178                 }
01179                 
01180                 return true;    
01181         }
01182 
01193         function removeInvalidRolefolders($a_invalid_rolefolders = NULL)
01194         {
01195                 global $ilias,$ilLog;
01196                 
01197                 // check mode: clean
01198                 if ($this->mode["clean"] !== true)
01199                 {
01200                         return false;
01201                 }
01202 
01203                 $this->writeScanLogLine("\nremoveInvalidRolefolders:");
01204 
01205                 if ($a_invalid_rolefolders === NULL and isset($this->invalid_rolefolders))
01206                 {
01207                         $a_invalid_rolefolders = $this->invalid_rolefolders;
01208                 }
01209 
01210                 // handle wrong input
01211                 if (!is_array($a_invalid_rolefolders)) 
01212                 {
01213                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01214                         return false;
01215                 }
01216 
01217                 // no invalid rolefolders found. do nothing
01218                 if (count($a_invalid_rolefolders) == 0)
01219                 {
01220                         $this->writeScanLogLine("none");
01221                         return false;
01222                 }
01223                 
01224 /*******************
01225 removal starts here
01226 ********************/
01227 
01228                 $removed = false;
01229                 
01230                 $message = sprintf('%s::removeInvalidRolefolders(): Started...',
01231                                                    get_class($this));
01232                 $ilLog->write($message,$ilLog->WARNING);
01233                 
01234                 foreach ($a_invalid_rolefolders as $rolf)
01235                 {
01236                         // restore ref_id in case of missing
01237                         if ($rolf["ref_id"] === NULL)
01238                         {
01239                                 $rolf["ref_id"] = $this->restoreReference($rolf["obj_id"]);
01240 
01241                                 $this->writeScanLogLine("Created missing reference '".$rolf["ref_id"]."' for rolefolder object '".$rolf["obj_id"]."'");
01242                         }
01243 
01244                         // now delete rolefolder
01245                         $obj_data =& $ilias->obj_factory->getInstanceByRefId($rolf["ref_id"]);
01246                         $obj_data->delete();
01247                         unset($obj_data);
01248                         $removed = true;
01249                         $this->writeScanLogLine("Removed invalid rolefolder '".$rolf["title"]."' (id=".$rolf["obj_id"].",ref=".$rolf["ref_id"].") from system");
01250                 }
01251                 
01252                 return $removed;
01253         }
01254 
01265         function restoreMissingObjects($a_missing_objects = NULL)
01266         {
01267                 global $ilias,$rbacadmin,$ilLog;
01268                 
01269                 // check mode: restore
01270                 if ($this->mode["restore"] !== true)
01271                 {
01272                         return false;
01273                 }
01274 
01275                 $this->writeScanLogLine("\nrestoreMissingObjects:");
01276 
01277                 if ($a_missing_objects === NULL and isset($this->missing_objects))
01278                 {
01279                         $a_missing_objects = $this->missing_objects;
01280                 }
01281 
01282                 // handle wrong input
01283                 if (!is_array($a_missing_objects)) 
01284                 {
01285                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01286                         return false;
01287                 }
01288 
01289                 // no missing objects found. do nothing
01290                 if (count($a_missing_objects) == 0)
01291                 {
01292                         $this->writeScanLogLine("none");
01293                         return false;
01294                 }
01295                 
01296 /*******************
01297 restore starts here
01298 ********************/
01299 
01300                 $restored = false;
01301                 
01302                 $message = sprintf('%s::restoreMissingObjects(): Started...',
01303                                                    get_class($this));
01304                 $ilLog->write($message,$ilLog->WARNING);
01305                 
01306                 foreach ($a_missing_objects as $missing_obj)
01307                 {
01308                         // restore ref_id in case of missing
01309                         if ($missing_obj["ref_id"] === NULL)
01310                         {
01311                                 $missing_obj["ref_id"] = $this->restoreReference($missing_obj["obj_id"]);
01312 
01313                                 $this->writeScanLogLine("Created missing reference '".$missing_obj["ref_id"]."' for object '".$missing_obj["obj_id"]."'");
01314                         }
01315 
01316                         // put in tree under RecoveryFolder if not on exclude list
01317                         if (!in_array($missing_obj["type"],$this->object_types_exclude))
01318                         {
01319                                 $rbacadmin->revokePermission($missing_obj["ref_id"]);
01320                                 $obj_data =& $ilias->obj_factory->getInstanceByRefId($missing_obj["ref_id"]);
01321                                 $obj_data->putInTree(RECOVERY_FOLDER_ID);
01322                                 $obj_data->setPermissions(RECOVERY_FOLDER_ID);
01323                                 $obj_data->initDefaultRoles();
01324                                 unset($obj_data);
01325                                 //$tree->insertNode($missing_obj["ref_id"],RECOVERY_FOLDER_ID);
01326                                 $restored = true;
01327                                 $this->writeScanLogLine("Restored object '".$missing_obj["title"]."' (id=".$missing_obj["obj_id"].",ref=".$missing_obj["ref_id"].") in 'Restored objects folder'");
01328                         }
01329                         
01330                         // TODO: process rolefolders
01331                 }
01332                 
01333                 return $restored;
01334         }
01335 
01345         function restoreReference($a_obj_id)
01346         {
01347                 global $ilLog;
01348 
01349                 if (empty($a_obj_id))
01350                 {
01351                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01352                         return false;
01353                 }
01354                 
01355                 $q = "INSERT INTO object_reference (ref_id,obj_id) VALUES ('0','".$a_obj_id."')";
01356                 $this->db->query($q);
01357 
01358                 $message = sprintf('%s::restoreReference(): new reference %s for obj_id %s created',
01359                                                    get_class($this),
01360                                                    $this->db->getLastInsertId(),
01361                                                    $_obj_id);
01362                 $ilLog->write($message,$ilLog->WARNING);
01363 
01364                 return $this->db->getLastInsertId();
01365         }
01366 
01377         function restoreUnboundObjects($a_unbound_objects = NULL)
01378         {
01379                 global $ilLog;
01380 
01381                 // check mode: restore
01382                 if ($this->mode["restore"] !== true)
01383                 {
01384                         return false;
01385                 }
01386 
01387                 $this->writeScanLogLine("\nrestoreUnboundObjects:");
01388 
01389                 if ($a_unbound_objects === NULL and isset($this->unbound_objects))
01390                 {
01391                         $a_unbound_objects = $this->unbound_objects;
01392                 }
01393 
01394                 // handle wrong input
01395                 if (!is_array($a_unbound_objects)) 
01396                 {
01397                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01398                         return false;
01399                 }
01400 
01401                 $message = sprintf('%s::restoreUnboundObjects(): Started...',
01402                                                    get_class($this));
01403                 $ilLog->write($message,$ilLog->WARNING);
01404                 
01405                 // start restore process
01406                 return $this->restoreSubTrees($a_unbound_objects);
01407         }
01408         
01418         function restoreTrash($a_deleted_objects = NULL)
01419         {
01420                 global $ilLog;
01421 
01422                 // check mode: restore
01423                 if ($this->mode["restore_trash"] !== true)
01424                 {
01425                         return false;
01426                 }
01427 
01428                 $this->writeScanLogLine("\nrestoreTrash:");
01429         
01430                 if ($a_deleted_objects === NULL and isset($this->deleted_objects))
01431                 {
01432                         $a_deleted_objects = $this->deleted_objects;
01433                 }
01434 
01435                 // handle wrong input
01436                 if (!is_array($a_deleted_objects)) 
01437                 {
01438                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01439                         return false;
01440                 }
01441 
01442                 $message = sprintf('%s::restoreTrash(): Started...',
01443                                                    get_class($this));
01444                 $ilLog->write($message,$ilLog->WARNING);
01445         
01446                 // start restore process
01447                 $restored = $this->restoreDeletedObjects($a_deleted_objects);
01448                 
01449                 if ($restored)
01450                 {
01451                         $q = "DELETE FROM tree WHERE tree!=1";
01452                         $this->db->query($q);
01453 
01454                         $message = sprintf('%s::restoreTrash(): Removed all trees with tree id <> 1',
01455                                                            get_class($this));
01456                         $ilLog->write($message,$ilLog->WARNING);
01457                 
01458                         $this->writeScanLogLine("Old tree entries removed");
01459                 }
01460                 
01461                 return $restored;
01462         }
01463         
01472         function restoreDeletedObjects($a_nodes)
01473         {
01474                 global $tree,$rbacadmin,$ilias,$ilLog;
01475 //vd($a_nodes);exit;
01476                 // handle wrong input
01477                 if (!is_array($a_nodes)) 
01478                 {
01479                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01480                         return false;
01481                 }
01482 
01483                 // no invalid parents found. do nothing
01484                 if (count($a_nodes) == 0)
01485                 {
01486                         $this->writeScanLogLine("none");
01487                         return false;
01488                 }
01489 
01490                 $message = sprintf('%s::restoreDeletedObjects()): Started...',
01491                                                    get_class($this));
01492                 $ilLog->write($message,$ilLog->WARNING);
01493 
01494                 // first delete all rolefolders
01495                 // don't save rolefolders, remove them
01496                 // TODO process ROLE_FOLDER_ID
01497                 foreach ($a_nodes as $key => $node)
01498                 {
01499                         if ($node["type"] == "rolf")
01500                         {
01501                                 // delete old tree entries
01502                                 $tree->deleteTree($node);
01503 
01504                                 $obj_data =& $ilias->obj_factory->getInstanceByRefId($node["child"]);
01505                                 $obj_data->delete();
01506                                 unset($a_nodes[$key]);
01507                         }       
01508                 }
01509                 
01510                 // process move
01511                 foreach ($a_nodes as $node)
01512                 {
01513                         // delete old tree entries
01514                         $tree->deleteTree($node);
01515                         
01516                         $rbacadmin->revokePermission($node["child"]);
01517                         $obj_data =& $ilias->obj_factory->getInstanceByRefId($node["child"]);
01518                         $obj_data->putInTree(RECOVERY_FOLDER_ID);
01519                         $obj_data->setPermissions(RECOVERY_FOLDER_ID);
01520                         $obj_data->initDefaultRoles();
01521                 }
01522                 
01523                 return true;
01524         }
01525 
01534         function restoreSubTrees ($a_nodes)
01535         {
01536                 global $tree,$rbacadmin,$ilias,$ilLog;
01537                 
01538                 // handle wrong input
01539                 if (!is_array($a_nodes)) 
01540                 {
01541                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01542                         return false;
01543                 }
01544 
01545                 // no invalid parents found. do nothing
01546                 if (count($a_nodes) == 0)
01547                 {
01548                         $this->writeScanLogLine("none");
01549                         return false;
01550                 }
01551                 
01552 /*******************
01553 restore starts here
01554 ********************/
01555 
01556                 $subnodes = array();
01557                 $topnode = array();
01558 
01559                 $message = sprintf('%s::restoreSubTrees(): Started...',
01560                                                    get_class($this));
01561                 $ilLog->write($message,$ilLog->WARNING);
01562                 
01563                 // process move subtree
01564                 foreach ($a_nodes as $node)
01565                 {
01566                         // get node data
01567                         $topnode = $tree->getNodeData($node["child"]);
01568                         
01569                         // don't save rolefolders, remove them
01570                         // TODO process ROLE_FOLDER_ID
01571                         if ($topnode["type"] == "rolf")
01572                         {
01573                                 $rolfObj = $ilias->obj_factory->getInstanceByRefId($topnode["child"]);
01574                                 $rolfObj->delete();
01575                                 unset($top_node);
01576                                 unset($rolfObj);
01577                                 continue;
01578                         }
01579 
01580                         // get subnodes of top nodes
01581                         $subnodes[$node["child"]] = $tree->getSubtree($topnode);
01582                 
01583                         // delete old tree entries
01584                         $tree->deleteTree($topnode);
01585                 }
01586 
01587                 // now move all subtrees to new location
01588                 // TODO: this whole put in place again stuff needs revision. Permission settings get lost.
01589                 foreach ($subnodes as $key => $subnode)
01590                 {
01591 
01592                         // first paste top_node ...
01593                         $rbacadmin->revokePermission($key);
01594                         $obj_data =& $ilias->obj_factory->getInstanceByRefId($key);
01595                         $obj_data->putInTree(RECOVERY_FOLDER_ID);
01596                         $obj_data->setPermissions(RECOVERY_FOLDER_ID);
01597                         $obj_data->initDefaultRoles();
01598                         
01599                         $this->writeScanLogLine("Object '".$obj_data->getId()."' restored.");
01600 
01601                         // ... remove top_node from list ...
01602                         array_shift($subnode);
01603                         
01604                         // ... insert subtree of top_node if any subnodes exist
01605                         if (count($subnode) > 0)
01606                         {
01607                                 foreach ($subnode as $node)
01608                                 {
01609                                         $rbacadmin->revokePermission($node["child"]);
01610                                         $obj_data =& $ilias->obj_factory->getInstanceByRefId($node["child"]);
01611                                         $obj_data->putInTree($node["parent"]);
01612                                         $obj_data->setPermissions($node["parent"]);
01613                                         $obj_data->initDefaultRoles();
01614                                         
01615                                         $this->writeScanLogLine("Object '".$obj_data->getId()."' restored.");
01616                                 }
01617                         }
01618                 }
01619 
01620                 // final clean up
01621                 $this->findInvalidChilds();
01622                 $this->removeInvalidChilds();
01623 
01624                 return true;
01625         }
01626         
01636         function purgeTrash($a_nodes = NULL)
01637         {
01638                 global $ilLog;
01639                 
01640                 // check mode: purge_trash
01641                 if ($this->mode["purge_trash"] !== true)
01642                 {
01643                         return false;
01644                 }
01645 
01646                 $this->writeScanLogLine("\npurgeTrash:");
01647         
01648                 if ($a_nodes === NULL and isset($this->deleted_objects))
01649                 {
01650                         $a_nodes = $this->deleted_objects;
01651                 }
01652 
01653                 $message = sprintf('%s::purgeTrash(): Started...',
01654                                                    get_class($this));
01655                 $ilLog->write($message,$ilLog->WARNING);
01656                 
01657                 // start purge process
01658                 return $this->purgeObjects($a_nodes);
01659         }
01660         
01670         function purgeUnboundObjects($a_nodes = NULL)
01671         {
01672                 global $ilLog;
01673                 
01674                 // check mode: purge
01675                 if ($this->mode["purge"] !== true)
01676                 {
01677                         return false;
01678                 }
01679 
01680                 $this->writeScanLogLine("\npurgeUnboundObjects:");
01681 
01682                 if ($a_nodes === NULL and isset($this->unbound_objects))
01683                 {
01684                         $a_nodes = $this->unbound_objects;
01685                 }
01686 
01687                 $message = sprintf('%s::purgeUnboundObjects(): Started...',
01688                                                    get_class($this));
01689                 $ilLog->write($message,$ilLog->WARNING);
01690                 
01691                 // start purge process
01692                 return $this->purgeObjects($a_nodes);
01693         }
01694 
01704         function purgeMissingObjects($a_nodes = NULL)
01705         {
01706                 global $ilLog;
01707                 
01708                 // check mode: purge
01709                 if ($this->mode["purge"] !== true)
01710                 {
01711                         return false;
01712                 }
01713 
01714                 $this->writeScanLogLine("\npurgeMissingObjects:");
01715 
01716                 if ($a_nodes === NULL and isset($this->missing_objects))
01717                 {
01718                         $a_nodes = $this->missing_objects;
01719                 }
01720 
01721                 $message = sprintf('%s::purgeMissingObjects(): Started...',
01722                                                    get_class($this));
01723                 $ilLog->write($message,$ilLog->WARNING);
01724                 
01725                 // start purge process
01726                 return $this->purgeObjects($a_nodes);
01727         }
01728         
01736         function purgeObjects($a_nodes)
01737         {
01738                 global $ilias,$ilLog;
01739 
01740                 // handle wrong input
01741                 if (!is_array($a_nodes)) 
01742                 {
01743                         $this->throwError(INVALID_PARAM, WARNING, DEBUG);
01744                         return false;
01745                 }
01746                 
01747                 // start delete process
01748                 foreach ($a_nodes as $node)
01749                 {
01750                         $ref_id = ($node["child"]) ? $node["child"] : $node["ref_id"];
01751                         $node_obj =& $ilias->obj_factory->getInstanceByRefId($ref_id,false);
01752                         
01753                         if ($node_obj === false)
01754                         {
01755                                 $this->invalid_objects[] = $node;
01756                                 continue;
01757                         }
01758 
01759                         $message = sprintf('%s::purgeObjects(): Removing object (id:%s ref:%s)',
01760                                                            get_class($this),
01761                                                            $ref_id,
01762                                                            $node_obj->getId);
01763                         $ilLog->write($message,$ilLog->WARNING);
01764                 
01765                         $node_obj->delete();
01766                         ilTree::_removeEntry($node["tree"],$ref_id);
01767                         
01768                         $this->writeScanLogLine("Object '".$node_obj->getId()."' deleted");
01769                 }
01770                 
01771                 $this->findInvalidChilds();
01772                 $this->removeInvalidChilds();
01773 
01774                 return true;
01775         }
01776 
01790         function initGapsInTree()
01791         {
01792                 global $tree,$ilLog;
01793                 
01794                 $message = sprintf('%s::initGapsInTree(): Started...',
01795                                                    get_class($this));
01796                 $ilLog->write($message,$ilLog->WARNING);
01797 
01798                 // check mode: clean
01799                 if ($this->mode["clean"] !== true)
01800                 {
01801                         return false;
01802                 }
01803                 $this->writeScanLogLine("\nrenumberTree:");
01804 
01805                 $tree->renumber(ROOT_FOLDER_ID);
01806 
01807                 $this->writeScanLogLine("done");
01808 
01809                 return true;
01810         }
01811 
01821         function handleErr($error)
01822         {
01823                 $call_loc = $error->backtrace[count($error->backtrace)-1];
01824                 $num_args = count($call_loc["args"]);
01825 
01826                 if ($num_args > 0)
01827                 {
01828                         foreach ($call_loc["args"] as $arg)
01829                         {
01830                                 $type = gettype($arg);
01831                                 
01832                                 switch ($type)
01833                                 {
01834                                         case "string":
01835                                                 $value = strlen($arg);
01836                                                 break;
01837 
01838                                         case "array":
01839                                                 $value = count($arg);
01840                                                 break;
01841 
01842                                         case "object":
01843                                                 $value = get_class($arg);
01844                                                 break;
01845 
01846                                         case "boolean":
01847                                                 $value = ($arg) ? "true" : "false";
01848                                                 break;
01849                                                 
01850                                         default:
01851                                                 $value = $arg;
01852                                                 break;
01853                                 }
01854                                 
01855                                 $arg_list[] = array(
01856                                                                         "type"  => $type,
01857                                                                         "value" => "(".$value.")"
01858                                                                         );
01859                         }
01860                         
01861                         foreach ($arg_list as $arg)
01862                         {
01863                                 $arg_str .= implode("",$arg)." ";
01864                         }
01865                 }
01866 
01867                 $err_msg = "<br/><b>".$error->getCode().":</b> ".$error->getMessage()." in ".$call_loc["class"].$call_loc["type"].$call_loc["function"]."()".
01868                                    "<br/>Called from: ".basename($call_loc["file"])." , line ".$call_loc["line"].
01869                                    "<br/>Passed parameters: [".$num_args."] ".$arg_str."<br/>";
01870                 printf($err_msg);
01871                 
01872                 if ($error->getUserInfo())
01873                 {
01874                         printf("<br/>Parameter details:");
01875                         echo "<pre>";
01876                         var_dump($call_loc["args"]);
01877                         echo "</pre>";
01878                 }
01879                 
01880                 if ($error->getCode() == FATAL)
01881                 {
01882                         exit();
01883                 }
01884         }
01885         
01886         function writeScanLogArray($a_arr)
01887         {
01888                 if (!$this->isLogEnabled())
01889                 {
01890                         return false;
01891                 }
01892                 
01893                 foreach ($a_arr as $entry)
01894                 {
01895                         $this->scan_log->write(implode("\t",$entry));           
01896                 }
01897         }
01898         
01899         function writeScanLogLine($a_msg)
01900         {
01901                 if (!$this->isLogEnabled())
01902                 {
01903                         return false;
01904                 }
01905                 
01906                 $this->scan_log->write($a_msg);
01907         }
01908 
01912         function hasScanLog()
01913         {
01914                 // file check
01915                 return is_file(CLIENT_DATA_DIR."/".$this->scan_log_file);
01916         }
01917 
01918         function readScanLog()
01919         {
01920                 // file check
01921                 if (! $this->hasScanLog())
01922                 {
01923                         return false;
01924                 }
01925 
01926                 $scanfile =& file(CLIENT_DATA_DIR."/".$this->scan_log_file);
01927                 if (!$scan_log =& $this->get_last_scan($scanfile))
01928                 {
01929                         return false;
01930                 }
01931                 // Ensure that memory is freed
01932                 unset($scanfile);
01933                 
01934                 return $scan_log;
01935         }
01936         
01937         function get_last_scan($a_scan_log)
01938         {
01939                 $logs = array_keys($a_scan_log,$this->scan_log_separator."\n");
01940                 
01941                 if (count($logs) > 0)
01942                 {
01943                         return array_slice($a_scan_log,array_pop($logs)+2);
01944                 }
01945                 
01946                 return false;
01947         }
01948         
01949         function checkTreeStructure($a_startnode = null)
01950         {
01951                 global $tree;
01952 
01953                 $this->writeScanLogLine("\nchecking tree structure is disabled");
01954                 
01955                 return false;
01956         }
01963         function dumpTree()
01964         {
01965                 $this->writeScanLogLine("BEGIN dumpTree:");
01966 
01967                 // collect nodes with duplicate child Id's
01968                 // (We use this, to mark these nodes later in the output as being
01969                 // erroneous.).
01970                 $q = 'SELECT child FROM tree GROUP BY child HAVING COUNT(*) > 1';
01971                 $r = $this->db->query($q);
01972                 $duplicateNodes = array();
01973                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
01974                 {
01975                         $duplicateNodes[] = $row->child;
01976                 }               
01977                 
01978                 // dump tree
01979                 $q = "SELECT tree.*,ref.ref_id,ref.obj_id AS refobj_id,dat.*,login "
01980                         ."FROM tree "
01981                         ."LEFT OUTER JOIN object_reference AS ref ON tree.child = ref.ref_id "
01982                         ."LEFT OUTER JOIN object_data AS dat ON ref.obj_id = dat.obj_id "
01983                         ."LEFT OUTER JOIN usr_data AS usr ON dat.owner = usr.usr_id "
01984                         ."ORDER BY tree, lft";
01985                 $r = $this->db->query($q);
01986                 
01987                 $this->writeScanLogLine(
01988                         '<table><tr>'
01989                         .'<td>tree, child, parent, lft, rgt, depth</td>'
01990                         .'<td>ref_id, ref.obj_id</td>'
01991                         .'<td>obj_id, type, title</td>'
01992                         .'</tr>'
01993                 );
01994                 
01995                 // We use a stack to represent the path to the current node.
01996                 // This allows us to do analyze the tree structure without having
01997                 // to implement a recursive algorithm.
01998                 $stack = array();
01999                 $error_count = 0;
02000                 $repository_tree_count = 0;
02001                 $trash_trees_count = 0;
02002                 $other_trees_count = 0;
02003                 $not_in_tree_count = 0;
02004 
02005                 // The previous number is used for gap checking
02006                 $previousNumber = 0; 
02007 
02008                 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
02009                 {
02010                         // If there is no entry in table tree for the object, we display it here
02011                         if (is_null($row->child))
02012                         {
02013                                 $not_in_tree_count++;
02014                                 $error_count++;
02015                                 $isRowOkay = false;
02016                                 $isParentOkay = false;
02017                                 $isLftOkay = false;
02018                                 $isRgtOkay = false;
02019                                 $isDepthOkay = false;
02020                                 
02021                                 $this->writeScanLogLine(
02022                                         '<tr>'
02023                                         .'<td>'
02024                                         .(($isRowOkay) ? '' : '<font color=#ff0000>')
02025                                         .$row->tree.', '
02026                                         .$row->child.', '
02027                                         .(($isParentOkay) ? '' : 'parent:<b>')
02028                                         .$row->parent
02029                                         .(($isParentOkay) ? '' : '</b>')
02030                                         .', '
02031                                         .(($isLftOkay) ? '' : 'lft:<b>')
02032                                         .$row->lft
02033                                         .(($isLftOkay) ? '' : '</b>')
02034                                         .', '
02035                                         .(($isRgtOkay) ? '' : 'rgt:<b>')
02036                                         .$row->rgt
02037                                         .(($isRgtOkay) ? '' : '</b>')
02038                                         .', '
02039                                         .(($isDepthOkay) ? '' : 'depth:<b>')
02040                                         .$row->depth
02041                                         .(($isDepthOkay) ? '' : '</b>')
02042                                         .(($isRowOkay) ? '' : '</font>')
02043                                         .'</td><td>'
02044                                         .(($isRowOkay) ? '' : '<font color=#ff0000>')
02045                                         .(($isRefRefOkay && $isChildOkay) ? '' : 'ref.ref_id:<b>')
02046                                         .$row->ref_id
02047                                         .(($isRefRefOkay && $isChildOkay) ? '' : '</b>')
02048                                         .', '
02049                                         .(($isRefObjOkay) ? '' : 'ref.obj_id:<b>')
02050                                         .$row->refobj_id
02051                                         .(($isRefObjOkay) ? '' : '</b>')
02052                                         .(($isRowOkay) ? '' : '<font color=#ff0000>')
02053                                         .'</td><td>'
02054                                         .(($isRowOkay) ? '' : '<font color=#ff0000>')
02055                                         .$indent
02056                                         .$row->obj_id.', '
02057                                         .$row->type.', '
02058                                         .$row->title.', '
02059                                         .$row->login
02060                                         .(($isRowOkay) ? '' : ' <b>*ERROR*</b><font color=#ff0000>')
02061                                         .'</td>'
02062                                         .'</tr>'
02063                                 );
02064                                 continue;
02065                         }
02066                 
02067                         // Update stack
02068                         // -------------------
02069                         $indent = "";
02070                         for ($i = 1; $i < $row->depth; $i++)
02071                         {
02072                                 $indent .= ". ";
02073                         }
02074                         
02075                         // Initialize the stack and the previous number if we are in a new tree
02076                         if (count($stack) == 0 || $stack[0]->tree != $row->tree) 
02077                         {
02078                                 $stack = array();
02079                                 $previousNumber = $row->lft - 1;
02080                         } 
02081                         // Pop old stack entries
02082                         while (count($stack) > 0 && $stack[count($stack) - 1]->rgt < $row->lft) 
02083                         {
02084                                 $popped = array_pop($stack);
02085                                 
02086                                 // check for gap
02087                                 $gap = $popped->rgt - $previousNumber - 1;
02088                                 if ($gap > 0)
02089                                 {
02090                                         $poppedIndent = "";
02091                                         for ($i = 1; $i < $popped->depth; $i++)
02092                                         {
02093                                                 $poppedIndent .= ". ";
02094                                         }
02095                                         $this->writeScanLogLine(
02096                                                 '<tr>'
02097                                                 .'<td colspan=2><div align="right">'
02098                                                 .'<font color=#00cc00>*gap* for '.($gap/2).' nodes at end of&nbsp;</font>'
02099                                                 .'</div></td>'
02100                                                 .'<td>'
02101                                                 .'<font color=#00cc00>'
02102                                                 .$poppedIndent
02103                                                 .$popped->obj_id.', '
02104                                                 .$popped->type.', '
02105                                                 .$popped->title.', '
02106                                                 .$popped->login
02107                                                 .'</font>'
02108                                                 .'</td>'
02109                                                 .'</tr>'
02110                                         );
02111                                 }
02112                                 $previousNumber = $popped->rgt;
02113                                 unset($popped);
02114                         }
02115 
02116                         // Check row integrity
02117                         // -------------------
02118                         $isRowOkay = true;
02119                         
02120                         // Check tree structure
02121                         $isChildOkay = true;
02122                         $isParentOkay = true;
02123                         $isLftOkay = true;
02124                         $isRgtOkay = true;
02125                         $isDepthOkay = true;
02126                         $isGap = false;
02127                         
02128                         if (count($stack) > 0) 
02129                         {                       
02130                                 $parent = $stack[count($stack) - 1];
02131                                 if ($parent->depth + 1 != $row->depth)
02132                                 {
02133                                         $isDepthOkay = false;
02134                                         $isRowOkay = false;
02135                                 }
02136                                 if ($parent->child != $row->parent)
02137                                 {
02138                                         $isParentOkay = false;
02139                                         $isRowOkay = false;
02140                                 }
02141                                 if ($parent->lft >= $row->lft)
02142                                 {
02143                                         $isLftOkay = false;
02144                                         $isRowOkay = false;
02145                                 }
02146                                 if ($parent->rgt <= $row->rgt)
02147                                 {
02148                                         $isRgtOkay = false;
02149                                         $isRowOkay = false;
02150                                 }
02151                         }
02152                         
02153                         // Check lft rgt
02154                         if ($row->lft >= $row->rgt)
02155                         {
02156                                 $isLftOkay = false;
02157                                 $isRgtOkay = false;
02158                                 $isRowOkay = false;
02159                         }
02160                         if (in_array($row->child, $duplicateNodes))
02161                         {
02162                                 $isChildOkay = false;
02163                                 $isRowOkay = false;
02164                         }
02165                         
02166                         // Check object reference
02167                         $isRefRefOkay = true;
02168                         $isRefObjOkay = true;
02169                         if ($row->ref_id == null)
02170                         {
02171                                 $isRefRefOkay = false;
02172                                 $isRowOkay = false;
02173                         }
02174                         if ($row->obj_id == null)
02175                         {
02176                                 $isRefObjOkay = false;
02177                                 $isRowOkay = false;
02178                         }
02179                         
02180                         if (! $isRowOkay)
02181                         {
02182                                 $error_count++;
02183                         }
02184 
02185                         // Check for gap between siblings,
02186                         // and eventually write a log line
02187                         $gap = $row->lft - $previousNumber - 1;
02188                         $previousNumber = $row->lft;
02189                         if ($gap > 0)
02190                         {
02191                                 $this->writeScanLogLine(
02192                                         '<tr>'
02193                                         .'<td colspan=2><div align="right">'
02194                                         .'<font color=#00cc00>*gap* for '.($gap/2).' nodes between&nbsp;</font>'
02195                                         .'</div></td>'
02196                                         .'<td>'
02197                                         .'<font color=#00cc00>siblings</font>'
02198                                         .'</td>'
02199                                         .'</tr>'
02200                                 );
02201                         }
02202                                                 
02203                         // Write log line
02204                         // -------------------
02205                         $this->writeScanLogLine(
02206                                 '<tr>'
02207                                 .'<td>'
02208                                 .(($isRowOkay) ? '' : '<font color=#ff0000>')
02209                                 .$row->tree.', '
02210                                 .$row->child.', '
02211                                 .(($isParentOkay) ? '' : 'parent:<b>')
02212                                 .$row->parent
02213                                 .(($isParentOkay) ? '' : '</b>')
02214                                 .', '
02215                                 .(($isLftOkay) ? '' : 'lft:<b>')
02216                                 .$row->lft
02217                                 .(($isLftOkay) ? '' : '</b>')
02218                                 .', '
02219                                 .(($isRgtOkay) ? '' : 'rgt:<b>')
02220                                 .$row->rgt
02221                                 .(($isRgtOkay) ? '' : '</b>')
02222                                 .', '
02223                                 .(($isDepthOkay) ? '' : 'depth:<b>')
02224                                 .$row->depth
02225                                 .(($isDepthOkay) ? '' : '</b>')
02226                                 .(($isRowOkay) ? '' : '</font>')
02227                                 .'</td><td>'
02228                                 .(($isRowOkay) ? '' : '<font color=#ff0000>')
02229                                 .(($isRefRefOkay && $isChildOkay) ? '' : 'ref.ref_id:<b>')
02230                                 .$row->ref_id
02231                                 .(($isRefRefOkay && $isChildOkay) ? '' : '</b>')
02232                                 .', '
02233                                 .(($isRefObjOkay) ? '' : 'ref.obj_id:<b>')
02234                                 .$row->refobj_id
02235                                 .(($isRefObjOkay) ? '' : '</b>')
02236                                 .(($isRowOkay) ? '' : '<font color=#ff0000>')
02237                                 .'</td><td>'
02238                                 .(($isRowOkay) ? '' : '<font color=#ff0000>')
02239                                 .$indent
02240                                 .$row->obj_id.', '
02241                                 .$row->type.', '
02242                                 .$row->title.', '
02243                                 .$row->login
02244                                 .(($isRowOkay) ? '' : ' <b>*ERROR*</b><font color=#ff0000>')
02245                                 .'</td>'
02246                                 .'</tr>'
02247                         );
02248 
02249                         // Update stack
02250                         // -------------------
02251                         // Push node on stack
02252                         $stack[] = $row;
02253                         
02254                         // Count nodes
02255                         // -----------------
02256                         if ($row->tree == 1)
02257                         {
02258                                 $repository_tree_count++;
02259                         }
02260                         else if ($row->tree < 0)
02261                         {
02262                                 $trash_trees_count++;
02263                         }
02264                         else
02265                         {
02266                                 $other_trees_count++;
02267                         }               
02268                         
02269                 }
02270                 //
02271                 // Pop remaining stack entries
02272                 while (count($stack) > 0) 
02273                 {
02274                         $popped = array_pop($stack);
02275                         
02276                         // check for gap
02277                         $gap = $popped->rgt - $previousNumber - 1;
02278                         if ($gap > 0)
02279                         {
02280                                 $poppedIndent = "";
02281                                 for ($i = 1; $i < $popped->depth; $i++)
02282                                 {
02283                                         $poppedIndent .= ". ";
02284                                 }
02285                                 $this->writeScanLogLine(
02286                                         '<tr>'
02287                                         .'<td colspan=2><div align="right">'
02288                                         .'<font color=#00cc00>*gap* for '.($gap/2).' nodes at end of&nbsp;</font>'
02289                                         .'</div></td>'
02290                                         .'<td>'
02291                                         .'<font color=#00cc00>'
02292                                         .$poppedIndent
02293                                         .$popped->obj_id.', '
02294                                         .$popped->type.', '
02295                                         .$popped->title
02296                                         .'</font>'
02297                                         .'</td>'
02298                                         .'</tr>'
02299                                 );
02300                         }
02301                         $previousNumber = $popped->rgt;
02302                         unset($popped);
02303                 }
02304                 
02305                 //
02306                 $this->writeScanLogLine("</table>");
02307 
02308                 if ($error_count > 0)
02309                 {
02310                         $this->writeScanLogLine('<font color=#ff0000>'.$error_count.' errors found while dumping tree.</font>');
02311                 }
02312                 else
02313                 {
02314                         $this->writeScanLogLine('No errors found while dumping tree.');
02315                 }
02316                 $this->writeScanLogLine("$repository_tree_count nodes in repository tree");             
02317                 $this->writeScanLogLine("$trash_trees_count nodes in trash trees");             
02318                 $this->writeScanLogLine("$other_trees_count nodes in other trees");             
02319                 $this->writeScanLogLine("$not_in_tree_count nodes are not in a tree");          
02320                 $this->writeScanLogLine("END dumpTree");
02321                 
02322                 return $error_count;    
02323         }
02324 } // END class.ilValidator
02325 ?>

Generated on Fri Dec 13 2013 13:52:08 for ILIAS Release_3_7_x_branch .rev 46817 by  doxygen 1.7.1