ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilDBUpdate.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
13 {
18 
24 
30 
34  function ilDBUpdate($a_db_handler = 0,$tmp_flag = false)
35  {
36  // workaround to allow setup migration
37  if ($a_db_handler)
38  {
39  $this->db =& $a_db_handler;
40 
41  if ($tmp_flag)
42  {
43  $this->PATH = "./";
44  }
45  else
46  {
47  $this->PATH = "./";
48  //$this->PATH = "../";
49  }
50  }
51  else
52  {
53  global $mySetup;
54  $this->db = $mySetup->db;
55  $this->PATH = "./";
56  }
57 
58  $this->getCurrentVersion();
59 
60  // get update file for current version
61  $updatefile = $this->getFileForStep($this->currentVersion + 1);
62 
63  $this->current_file = $updatefile;
64  $this->DB_UPDATE_FILE = $this->PATH."setup/sql/".$updatefile;
65 
66  //
67  // NOTE: IF YOU SET THIS TO THE NEWEST FILE, CHANGE ALSO getFileForStep()
68  //
69  $this->LAST_UPDATE_FILE = $this->PATH."setup/sql/dbupdate_04.php";
70 
71  $this->readDBUpdateFile();
72  $this->readLastUpdateFile();
73  $this->readFileVersion();
74  }
75 
79  function getFileForStep($a_version)
80  {
81  //
82  // NOTE: IF YOU ADD A NEW FILE HERE, CHANGE ALSO THE CONSTRUCTOR
83  //
84  if ((int)$a_version > 4182) // last number in previous file
85  {
86  return "dbupdate_04.php";
87  }
88  else if ((int)$a_version > 2948) // last number in previous file
89  {
90  return "dbupdate_03.php";
91  }
92  else if ((int)$a_version > 864) // last number in previous file
93  {
94  return "dbupdate_02.php";
95  }
96  else
97  {
98  return "dbupdate.php";
99  }
100  }
101 
105  function initStep($i)
106  {
107  //
108  }
109 
115  function _DBUpdate()
116  {
117  $this->db->disconnect();
118  }
119 
120  function readDBUpdateFile()
121  {
122  if (!file_exists($this->DB_UPDATE_FILE))
123  {
124  $this->error = "no_db_update_file";
125  $this->filecontent = array();
126  return false;
127  }
128 
129  $this->filecontent = @file($this->DB_UPDATE_FILE);
130  return true;
131  }
132 
134  {
135  if (!file_exists($this->LAST_UPDATE_FILE))
136  {
137  $this->error = "no_last_update_file";
138  $this->lastfilecontent = array();
139  return false;
140  }
141 
142  $this->lastfilecontent = @file($this->LAST_UPDATE_FILE);
143  return true;
144  }
145 
146  function getCurrentVersion()
147  {
148  $GLOBALS["ilDB"] = $this->db;
149  include_once './Services/Administration/classes/class.ilSetting.php';
150  $set = new ilSetting("common", true);
151  $this->currentVersion = (integer) $set->get("db_version");
152  return $this->currentVersion;
153  }
154 
155  function setCurrentVersion ($a_version)
156  {
157  include_once './Services/Administration/classes/class.ilSetting.php';
158  $set = new ilSetting("common", true);
159  $set->set("db_version", $a_version);
160  $this->currentVersion = $a_version;
161 
162  return true;
163  }
164 
170  function setRunningStatus($a_nr)
171  {
172  include_once './Services/Administration/classes/class.ilSetting.php';
173  $set = new ilSetting("common", true);
174  $set->set("db_update_running", $a_nr);
175  $this->db_update_running = $a_nr;
176  }
177 
183  function getRunningStatus()
184  {
185  include_once './Services/Administration/classes/class.ilSetting.php';
186  $set = new ilSetting("common", true);
187  $this->db_update_running = (integer) $set->get("db_update_running");
188 
189  return $this->db_update_running;
190  }
191 
196  {
197  include_once './Services/Administration/classes/class.ilSetting.php';
198  $set = new ilSetting("common", true);
199  $set->set("db_update_running", 0);
200  $this->db_update_running = 0;
201  }
202 
203  function readFileVersion()
204  {
205  //go through filecontent and search for last occurence of <#x>
206  reset($this->lastfilecontent);
207  $regs = array();
208  foreach ($this->lastfilecontent as $row)
209  {
210  if (ereg("^<#([0-9]+)>", $row, $regs))
211  {
212  $version = $regs[1];
213  }
214  }
215 
216  $this->fileVersion = (integer) $version;
217  return $this->fileVersion;
218  }
219 
223  function getFileVersion()
224  {
225  return $this->fileVersion;
226  }
227 
234  function execQuery($db,$str)
235  {
236  $sql = explode("\n",trim($str));
237  for ($i=0; $i<count($sql); $i++)
238  {
239  $sql[$i] = trim($sql[$i]);
240  if ($sql[$i] != "" && substr($sql[$i],0,1)!="#")
241  {
242  //take line per line, until last char is ";"
243  if (substr($sql[$i],-1)==";")
244  {
245  //query is complete
246  $q .= " ".substr($sql[$i],0,-1);
247  $check = $this->checkQuery($q);
248  if ($check === true)
249  {
250  $r = $db->query($q);
251  if (MDB2::isError($r))
252  {
253  $this->error = $r->getMessage();
254  return false;
255  }
256  }
257  else
258  {
259  $this->error = $check;
260  return false;
261  }
262  unset($q);
263  } //if
264  else
265  {
266  $q .= " ".$sql[$i];
267  } //else
268  } //if
269  } //for
270  if ($q != "")
271  {
272  echo "incomplete_statement: ".$q."<br>";
273  return false;
274  }
275  return true;
276  }
277 
281  function checkQuery($q)
282  {
283  return true;
284  }
285 
289  function applyUpdate($a_break = 0)
290  {
291  global $ilCtrlStructureReader, $ilMySQLAbstraction;
292 
293  include_once './Services/Database/classes/class.ilMySQLAbstraction.php';
294 
295  $ilMySQLAbstraction = new ilMySQLAbstraction();
296  $GLOBALS['ilMySQLAbstraction'] = $ilMySQLAbstraction;
297 
298  $f = $this->fileVersion;
300 
301  if ($a_break > $this->currentVersion &&
302  $a_break < $this->fileVersion)
303  {
304  $f = $a_break;
305  }
306 
307  if ($c < $f)
308  {
309  $msg = array();
310  for ($i=($c+1); $i<=$f; $i++)
311  {
312  // check wether next update file must be loaded
313  if ($this->current_file != $this->getFileForStep($i))
314  {
315  $this->DB_UPDATE_FILE = $this->PATH."setup/sql/".$this->getFileForStep($i);
316  $this->readDBUpdateFile();
317  }
318 
319  $this->initStep($i);
320 
321  if ($this->applyUpdateNr($i) == false)
322  {
323  $msg[] = array(
324  "msg" => "update_error: ".$this->error,
325  "nr" => $i
326  );
327  $this->updateMsg = $msg;
328  return false;
329  }
330  else
331  {
332  $msg[] = array(
333  "msg" => "update_applied",
334  "nr" => $i
335  );
336  }
337  }
338 
339  $this->updateMsg = $msg;
340  }
341  else
342  {
343  $this->updateMsg = "no_changes";
344  }
345 
346  if ($f < $this->fileVersion)
347  {
348  return true;
349  }
350  else
351  {
352  return $this->loadXMLInfo();
353  }
354  }
355 
356  function loadXMLInfo()
357  {
358  global $ilCtrlStructureReader;
359 
360  // read module and service information into db
361  require_once "./setup/classes/class.ilModuleReader.php";
362  require_once "./setup/classes/class.ilServiceReader.php";
363  require_once "./setup/classes/class.ilCtrlStructureReader.php";
364 
365  require_once "./Services/Component/classes/class.ilModule.php";
366  require_once "./Services/Component/classes/class.ilService.php";
369 
370  $mr = new ilModuleReader("", "", "");
371  $mr->clearTables();
372  foreach($modules as $module)
373  {
374  $mr = new ilModuleReader(ILIAS_ABSOLUTE_PATH."/Modules/".$module["subdir"]."/module.xml",
375  $module["subdir"], "Modules");
376  $mr->getModules();
377  unset($mr);
378  }
379 
380  $sr = new ilServiceReader("", "", "");
381  $sr->clearTables();
382  foreach($services as $service)
383  {
384  $sr = new ilServiceReader(ILIAS_ABSOLUTE_PATH."/Services/".$service["subdir"]."/service.xml",
385  $service["subdir"], "Services");
386  $sr->getServices();
387  unset($sr);
388  }
389 
390  $ilCtrlStructureReader->readStructure();
391 
392  return true;
393  }
394 
401  function applyUpdateNr($nr, $hotfix = false, $custom_update = false)
402  {
403  global $ilDB,$ilErr,$ilUser,$ilCtrlStructureReader,$ilModuleReader,$ilMySQLAbstraction;
404 
405  //search for desired $nr
406  reset($this->filecontent);
407 
408  if (!$hotfix)
409  {
410  $this->setRunningStatus($nr);
411  }
412 
413  //init
414  $i = 0;
415 
416  //go through filecontent
417  while (!ereg("^<#".$nr.">", $this->filecontent[$i]) && $i<count($this->filecontent))
418  {
419  $i++;
420  }
421 
422  //update not found
423  if ($i == count($this->filecontent))
424  {
425  $this->error = "update_not_found";
426  return false;
427  }
428 
429  $i++;
430 
431  //update found, now extract this update to a new array
432  $update = array();
433  while ($i<count($this->filecontent) && !ereg("^<#".($nr+1).">", $this->filecontent[$i]))
434  {
435  $update[] = trim($this->filecontent[$i]);
436  $i++;
437  }
438 
439  //now you have the update, now process it
440  $sql = array();
441  $php = array();
442  $mode = "sql";
443 
444  foreach ($update as $row)
445  {
446  if (ereg("<\?php", $row))
447  {
448  if (count($sql)>0)
449  {
450  if ($this->execQuery($this->db, implode("\n", $sql)) == false)
451  {
452  $this->error = $this->error;
453  return false;
454  }
455  $sql = array();
456  }
457  $mode = "php";
458  }
459  elseif (ereg("\?>", $row))
460  {
461  if (count($php)>0)
462  {
463  $code = implode("\n", $php);
464  if (eval($code) === false)
465  {
466  $this->error = "Parse error: ".$code;
467  return false;
468  }
469  $php = array();
470  }
471  $mode = "sql";
472 
473  }
474  else
475  {
476  if ($mode == "sql")
477  {
478  $sql[] = $row;
479  }
480 
481  if ($mode == "php")
482  {
483  $php[] = $row;
484  }
485  } //else
486  } //foreach
487 
488  if ($mode == "sql" && count($sql) > 0)
489  {
490  if ($this->execQuery($this->db, implode("\n", $sql)) == false)
491  {
492  $this->error = "dump_error: ".$this->error;
493  return false;
494  }
495  }
496 
497  //increase db_Version number
498  if (!$hotfix && !$custom_update)
499  {
500  $this->setCurrentVersion($nr);
501  }
502  elseif($hotfix)
503  {
504  $this->setHotfixCurrentVersion($nr);
505  }
506  elseif($custom_update)
507  {
508  $this->setCustomUpdatesCurrentVersion($nr);
509  }
510 
511  if (!$hotfix && !$custom_update)
512  {
513  $this->clearRunningStatus();
514  }
515  //$this->currentVersion = $ilias->getSetting("db_version");
516 
517  return true;
518 
519  }
520 
522  {
523  if ($this->fileVersion > $this->currentVersion)
524  return false;
525  else
526  return true;
527  }
528 
529  function getTables()
530  {
531  $a = array();
532 
533  $query = "SHOW TABLES";
534  $res = $this->db->query($query);
535  while ($row = $res->fetchRow())
536  {
537  $status = $this->getTableStatus($row[0]);
538  $a[] = array(
539  "name" => $status["Table"],
540  "table" => $row[0],
541  "status" => $status["Msg_text"]
542  );
543  }
544  return $a;
545  }
546 
547  function getTableStatus($table)
548  {
549  $a = array();
550 
551  $query = "ANALYZE TABLE ".$table;
552  $res = $this->db->query($query);
553  $row = $res->fetchRow(DB_FETCHMODE_ASSOC);
554  return $row;
555  }
556 
557  function optimizeTables($tables)
558  {
559  $msg = array();
560  foreach ($_POST["tables"] as $key => $value)
561  {
562  $query = "OPTIMIZE TABLE ".$key;
563  $res = $this->db->query($query);
564  $msg[] = "table $key: ok";
565  }
566  return $msg;
567  }
568 
572 
573 
578  {
579  $this->readHotfixInfo();
580  return $this->hotfix_current_version;
581  }
582 
586  function setHotfixCurrentVersion($a_version)
587  {
588  $this->readHotfixInfo();
589  $this->hotfix_setting->set("db_hotfixes_".
590  $this->hotfix_version[0]."_".$this->hotfix_version[1], $a_version);
591  $this->hotfix_current_version = $a_version;
592  return true;
593  }
594 
599  {
600  $this->readHotfixInfo();
601  return $this->hotfix_file_version;
602  }
603 
607  function readHotfixFileVersion($a_file_content)
608  {
609  //go through filecontent and search for last occurence of <#x>
610  reset($a_file_content);
611  $regs = array();
612  foreach ($a_file_content as $row)
613  {
614  if (ereg("^<#([0-9]+)>", $row, $regs))
615  {
616  $version = $regs[1];
617  }
618  }
619 
620  return (integer) $version;
621  }
622 
626  function readHotfixInfo($a_force = false)
627  {
628  if ($this->hotfix_info_read && !$a_force)
629  {
630  return;
631  }
632  include_once './Services/Administration/classes/class.ilSetting.php';
633  $GLOBALS["ilDB"] = $this->db;
634  $this->hotfix_setting = new ilSetting("common", true);
635  $ilias_version = ILIAS_VERSION_NUMERIC;
636  $version_array = explode(".", $ilias_version);
637  $this->hotfix_version[0] = $version_array[0];
638  $this->hotfix_version[1] = $version_array[1];
639  $hotfix_file = $this->PATH."setup/sql/".$this->hotfix_version[0]."_".$this->hotfix_version[1]."_hotfixes.php";
640  if (is_file($hotfix_file))
641  {
642  $this->hotfix_content = @file($hotfix_file);
643  $this->hotfix_current_version = (int) $this->hotfix_setting->get("db_hotfixes_".
644  $this->hotfix_version[0]."_".$this->hotfix_version[1]);
645  $this->hotfix_file_version = $this->readHotfixFileVersion($this->hotfix_content);
646  }
647  $this->hotfix_info_read = true;
648  }
649 
653  function hotfixAvailable()
654  {
655  $this->readHotfixInfo();
656  if ($this->hotfix_file_version > $this->hotfix_current_version)
657  {
658  return true;
659  }
660  return false;
661  }
662 
666  function applyHotfix()
667  {
668  global $ilCtrlStructureReader, $ilMySQLAbstraction;
669 
670  include_once './Services/Database/classes/class.ilMySQLAbstraction.php';
671 
672  $ilMySQLAbstraction = new ilMySQLAbstraction();
673  $GLOBALS['ilMySQLAbstraction'] = $ilMySQLAbstraction;
674 
675  $this->readHotfixInfo(true);
676 
677  $f = $this->getHotfixFileVersion();
678  $c = $this->getHotfixCurrentVersion();
679 
680  if ($c < $f)
681  {
682  $msg = array();
683  for ($i=($c+1); $i<=$f; $i++)
684  {
685 // $this->initStep($i); // nothings happens here
686 
687  $this->filecontent = $this->hotfix_content;
688 
689  if ($this->applyUpdateNr($i, true) == false)
690  {
691  $msg[] = array(
692  "msg" => "update_error: ".$this->error,
693  "nr" => $i
694  );
695  $this->updateMsg = $msg;
696  return false;
697  }
698  else
699  {
700  $msg[] = array(
701  "msg" => "hotfix_applied",
702  "nr" => $i
703  );
704  }
705  }
706 
707  $this->updateMsg = $msg;
708  }
709  else
710  {
711  $this->updateMsg = "no_changes";
712  }
713 
714  return $this->loadXMLInfo();
715  }
716 
718  {
719  $this->readCustomUpdatesInfo();
720  return $this->custom_updates_current_version;
721  }
722 
723  public function setCustomUpdatesCurrentVersion($a_version)
724  {
725  $this->readCustomUpdatesInfo();
726  $this->custom_updates_setting->set('db_version_custom', $a_version);
727  $this->custom_updates_current_version = $a_version;
728  return true;
729  }
730 
731  public function getCustomUpdatesFileVersion()
732  {
733  $this->readCustomUpdatesInfo();
734  return $this->custom_updates_file_version;
735  }
736 
737  public function readCustomUpdatesFileVersion($a_file_content)
738  {
739  //go through filecontent and search for last occurence of <#x>
740  reset($a_file_content);
741  $regs = array();
742  foreach ($a_file_content as $row)
743  {
744  if (ereg("^<#([0-9]+)>", $row, $regs))
745  {
746  $version = $regs[1];
747  }
748  }
749 
750  return (integer) $version;
751  }
752 
753  public function readCustomUpdatesInfo($a_force = false)
754  {
755  if ($this->custom_updates_info_read && !$a_force)
756  {
757  return;
758  }
759  include_once './Services/Administration/classes/class.ilSetting.php';
760  $GLOBALS["ilDB"] = $this->db;
761  $this->custom_updates_setting = new ilSetting();
762  $custom_updates_file = $this->PATH."setup/sql/dbupdate_custom.php";
763  if (is_file($custom_updates_file))
764  {
765  $this->custom_updates_content = @file($custom_updates_file);
766  $this->custom_updates_current_version = (int) $this->custom_updates_setting->get('db_version_custom', 0);
767  $this->custom_updates_file_version = $this->readCustomUpdatesFileVersion($this->custom_updates_content);
768  }
769  $this->custom_updates_info_read = true;
770  }
771 
772  public function customUpdatesAvailable()
773  {
774  // trunk does not support custom updates
775 // return false;
776 
777  $this->readCustomUpdatesInfo();
778  if ($this->custom_updates_file_version > $this->custom_updates_current_version)
779  {
780  return true;
781  }
782  return false;
783  }
784 
785  public function applyCustomUpdates()
786  {
787  global $ilCtrlStructureReader, $ilMySQLAbstraction;
788 
789  include_once './Services/Database/classes/class.ilMySQLAbstraction.php';
790 
791  $ilMySQLAbstraction = new ilMySQLAbstraction();
792  $GLOBALS['ilMySQLAbstraction'] = $ilMySQLAbstraction;
793 
794  $this->readCustomUpdatesInfo(true);
795 
796  $f = $this->getCustomUpdatesFileVersion();
797  $c = $this->getCustomUpdatesCurrentVersion();
798 
799  if ($c < $f)
800  {
801  $msg = array();
802  for ($i=($c+1); $i<=$f; $i++)
803  {
804 // $this->initStep($i); // nothings happens here
805 
806  $this->filecontent = $this->custom_updates_content;
807 
808  if ($this->applyUpdateNr($i, false, true) == false)
809  {
810  $msg[] = array(
811  "msg" => "update_error: ".$this->error,
812  "nr" => $i
813  );
814  $this->updateMsg = $msg;
815  return false;
816  }
817  else
818  {
819  $msg[] = array(
820  "msg" => "custom_update_applied",
821  "nr" => $i
822  );
823  }
824  }
825 
826  $this->updateMsg = $msg;
827  }
828  else
829  {
830  $this->updateMsg = "no_changes";
831  }
832 
833  return $this->loadXMLInfo();
834  }
835 
841  function getUpdateSteps($a_break = 0)
842  {
843  global $ilCtrlStructureReader, $ilMySQLAbstraction;
844 
845  $str = "";
846 
847  $f = $this->fileVersion;
849 
850  if ($a_break > $this->currentVersion &&
851  $a_break < $this->fileVersion)
852  {
853  $f = $a_break;
854  }
855 
856  if ($c < $f)
857  {
858  $msg = array();
859  for ($i=($c+1); $i<=$f; $i++)
860  {
861  // check wether next update file must be loaded
862  if ($this->current_file != $this->getFileForStep($i))
863  {
864  $this->DB_UPDATE_FILE = $this->PATH."setup/sql/".$this->getFileForStep($i);
865  $this->readDBUpdateFile();
866  }
867 
868  $str.= $this->getUpdateStepNr($i);
869  }
870 
871  }
872  return $str;
873  }
874 
880  function getHotfixSteps()
881  {
882  $this->readHotfixInfo(true);
883 
884  $str = "";
885 
886  $f = $this->getHotfixFileVersion();
887  $c = $this->getHotfixCurrentVersion();
888 
889  if ($c < $f)
890  {
891  $msg = array();
892  for ($i=($c+1); $i<=$f; $i++)
893  {
894  $this->filecontent = $this->hotfix_content;
895 
896  $str.= $this->getUpdateStepNr($i, true);
897  }
898  }
899 
900  return $str;
901  }
902 
903 
907  function getUpdateStepNr($nr, $hotfix = false, $custom_update = false)
908  {
909  global $ilDB,$ilErr,$ilUser,$ilCtrlStructureReader,$ilModuleReader,$ilMySQLAbstraction;
910 
911  $str = "";
912 
913  //search for desired $nr
914  reset($this->filecontent);
915 
916  //init
917  $i = 0;
918 
919  //go through filecontent
920  while (!ereg("^<#".$nr.">", $this->filecontent[$i]) && $i<count($this->filecontent))
921  {
922  $i++;
923  }
924 
925  //update not found
926  if ($i == count($this->filecontent))
927  {
928  return false;
929  }
930 
931  $i++;
932 
933  //update found, now extract this update to a new array
934  $update = array();
935  while ($i<count($this->filecontent) && !ereg("^<#".($nr+1).">", $this->filecontent[$i]))
936  {
937  $str.= $this->filecontent[$i];
938  $i++;
939  }
940 
941  return "<pre><b><#".$nr."></b>\n".htmlentities($str)."</pre>";
942  }
943 
944 } // END class.DBUdate
945 ?>