ILIAS  release_4-3 Revision
 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_03.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 > 2948) // last number in previous file
85  {
86  return "dbupdate_03.php";
87  }
88  else if ((int)$a_version > 864) // last number in previous file
89  {
90  return "dbupdate_02.php";
91  }
92  else
93  {
94  return "dbupdate.php";
95  }
96  }
97 
101  function initStep($i)
102  {
103  //
104  }
105 
111  function _DBUpdate()
112  {
113  $this->db->disconnect();
114  }
115 
116  function readDBUpdateFile()
117  {
118  if (!file_exists($this->DB_UPDATE_FILE))
119  {
120  $this->error = "no_db_update_file";
121  $this->filecontent = array();
122  return false;
123  }
124 
125  $this->filecontent = @file($this->DB_UPDATE_FILE);
126  return true;
127  }
128 
130  {
131  if (!file_exists($this->LAST_UPDATE_FILE))
132  {
133  $this->error = "no_last_update_file";
134  $this->lastfilecontent = array();
135  return false;
136  }
137 
138  $this->lastfilecontent = @file($this->LAST_UPDATE_FILE);
139  return true;
140  }
141 
142  function getCurrentVersion()
143  {
144  $GLOBALS["ilDB"] = $this->db;
145  include_once './Services/Administration/classes/class.ilSetting.php';
146  $set = new ilSetting("common", true);
147  $this->currentVersion = (integer) $set->get("db_version");
148  return $this->currentVersion;
149  }
150 
151  function setCurrentVersion ($a_version)
152  {
153  include_once './Services/Administration/classes/class.ilSetting.php';
154  $set = new ilSetting("common", true);
155  $set->set("db_version", $a_version);
156  $this->currentVersion = $a_version;
157 
158  return true;
159  }
160 
166  function setRunningStatus($a_nr)
167  {
168  include_once './Services/Administration/classes/class.ilSetting.php';
169  $set = new ilSetting("common", true);
170  $set->set("db_update_running", $a_nr);
171  $this->db_update_running = $a_nr;
172  }
173 
179  function getRunningStatus()
180  {
181  include_once './Services/Administration/classes/class.ilSetting.php';
182  $set = new ilSetting("common", true);
183  $this->db_update_running = (integer) $set->get("db_update_running");
184 
185  return $this->db_update_running;
186  }
187 
192  {
193  include_once './Services/Administration/classes/class.ilSetting.php';
194  $set = new ilSetting("common", true);
195  $set->set("db_update_running", 0);
196  $this->db_update_running = 0;
197  }
198 
199  function readFileVersion()
200  {
201  //go through filecontent and search for last occurence of <#x>
202  reset($this->lastfilecontent);
203  $regs = array();
204  foreach ($this->lastfilecontent as $row)
205  {
206  if (ereg("^<#([0-9]+)>", $row, $regs))
207  {
208  $version = $regs[1];
209  }
210  }
211 
212  $this->fileVersion = (integer) $version;
213  return $this->fileVersion;
214  }
215 
219  function getFileVersion()
220  {
221  return $this->fileVersion;
222  }
223 
230  function execQuery($db,$str)
231  {
232  $sql = explode("\n",trim($str));
233  for ($i=0; $i<count($sql); $i++)
234  {
235  $sql[$i] = trim($sql[$i]);
236  if ($sql[$i] != "" && substr($sql[$i],0,1)!="#")
237  {
238  //take line per line, until last char is ";"
239  if (substr($sql[$i],-1)==";")
240  {
241  //query is complete
242  $q .= " ".substr($sql[$i],0,-1);
243  $check = $this->checkQuery($q);
244  if ($check === true)
245  {
246  $r = $db->query($q);
247  if (MDB2::isError($r))
248  {
249  $this->error = $r->getMessage();
250  return false;
251  }
252  }
253  else
254  {
255  $this->error = $check;
256  return false;
257  }
258  unset($q);
259  } //if
260  else
261  {
262  $q .= " ".$sql[$i];
263  } //else
264  } //if
265  } //for
266  if ($q != "")
267  {
268  echo "incomplete_statement: ".$q."<br>";
269  return false;
270  }
271  return true;
272  }
273 
277  function checkQuery($q)
278  {
279  return true;
280  }
281 
285  function applyUpdate($a_break = 0)
286  {
287  global $ilCtrlStructureReader, $ilMySQLAbstraction;
288 
289  include_once './Services/Database/classes/class.ilMySQLAbstraction.php';
290 
291  $ilMySQLAbstraction = new ilMySQLAbstraction();
292  $GLOBALS['ilMySQLAbstraction'] = $ilMySQLAbstraction;
293 
294  $f = $this->fileVersion;
296 
297  if ($a_break > $this->currentVersion &&
298  $a_break < $this->fileVersion)
299  {
300  $f = $a_break;
301  }
302 
303  if ($c < $f)
304  {
305  $msg = array();
306  for ($i=($c+1); $i<=$f; $i++)
307  {
308  // check wether next update file must be loaded
309  if ($this->current_file != $this->getFileForStep($i))
310  {
311  $this->DB_UPDATE_FILE = $this->PATH."setup/sql/".$this->getFileForStep($i);
312  $this->readDBUpdateFile();
313  }
314 
315  $this->initStep($i);
316 
317  if ($this->applyUpdateNr($i) == false)
318  {
319  $msg[] = array(
320  "msg" => "update_error: ".$this->error,
321  "nr" => $i
322  );
323  $this->updateMsg = $msg;
324  return false;
325  }
326  else
327  {
328  $msg[] = array(
329  "msg" => "update_applied",
330  "nr" => $i
331  );
332  }
333  }
334 
335  $this->updateMsg = $msg;
336  }
337  else
338  {
339  $this->updateMsg = "no_changes";
340  }
341 
342  if ($f < $this->fileVersion)
343  {
344  return true;
345  }
346  else
347  {
348  return $this->loadXMLInfo();
349  }
350  }
351 
352  function loadXMLInfo()
353  {
354  global $ilCtrlStructureReader;
355 
356  // read module and service information into db
357  require_once "./setup/classes/class.ilModuleReader.php";
358  require_once "./setup/classes/class.ilServiceReader.php";
359  require_once "./setup/classes/class.ilCtrlStructureReader.php";
360 
361  require_once "./Services/Component/classes/class.ilModule.php";
362  require_once "./Services/Component/classes/class.ilService.php";
365 
367  foreach($modules as $module)
368  {
369  $mr = new ilModuleReader(ILIAS_ABSOLUTE_PATH."/Modules/".$module["subdir"]."/module.xml",
370  $module["subdir"], "Modules");
371  $mr->getModules();
372  unset($mr);
373  }
374 
376  foreach($services as $service)
377  {
378  $sr = new ilServiceReader(ILIAS_ABSOLUTE_PATH."/Services/".$service["subdir"]."/service.xml",
379  $service["subdir"], "Services");
380  $sr->getServices();
381  unset($sr);
382  }
383 
384  $ilCtrlStructureReader->readStructure();
385 
386  return true;
387  }
388 
395  function applyUpdateNr($nr, $hotfix = false, $custom_update = false)
396  {
397  global $ilDB,$ilErr,$ilUser,$ilCtrlStructureReader,$ilModuleReader,$ilMySQLAbstraction;
398 
399  //search for desired $nr
400  reset($this->filecontent);
401 
402  if (!$hotfix)
403  {
404  $this->setRunningStatus($nr);
405  }
406 
407  //init
408  $i = 0;
409 
410  //go through filecontent
411  while (!ereg("^<#".$nr.">", $this->filecontent[$i]) && $i<count($this->filecontent))
412  {
413  $i++;
414  }
415 
416  //update not found
417  if ($i == count($this->filecontent))
418  {
419  $this->error = "update_not_found";
420  return false;
421  }
422 
423  $i++;
424 
425  //update found, now extract this update to a new array
426  $update = array();
427  while ($i<count($this->filecontent) && !ereg("^<#".($nr+1).">", $this->filecontent[$i]))
428  {
429  $update[] = trim($this->filecontent[$i]);
430  $i++;
431  }
432 
433  //now you have the update, now process it
434  $sql = array();
435  $php = array();
436  $mode = "sql";
437 
438  foreach ($update as $row)
439  {
440  if (ereg("<\?php", $row))
441  {
442  if (count($sql)>0)
443  {
444  if ($this->execQuery($this->db, implode("\n", $sql)) == false)
445  {
446  $this->error = $this->error;
447  return false;
448  }
449  $sql = array();
450  }
451  $mode = "php";
452  }
453  elseif (ereg("\?>", $row))
454  {
455  if (count($php)>0)
456  {
457  $code = implode("\n", $php);
458  if (eval($code) === false)
459  {
460  $this->error = "Parse error: ".$code;
461  return false;
462  }
463  $php = array();
464  }
465  $mode = "sql";
466 
467  }
468  else
469  {
470  if ($mode == "sql")
471  {
472  $sql[] = $row;
473  }
474 
475  if ($mode == "php")
476  {
477  $php[] = $row;
478  }
479  } //else
480  } //foreach
481 
482  if ($mode == "sql" && count($sql) > 0)
483  {
484  if ($this->execQuery($this->db, implode("\n", $sql)) == false)
485  {
486  $this->error = "dump_error: ".$this->error;
487  return false;
488  }
489  }
490 
491  //increase db_Version number
492  if (!$hotfix && !$custom_update)
493  {
494  $this->setCurrentVersion($nr);
495  }
496  elseif($hotfix)
497  {
498  $this->setHotfixCurrentVersion($nr);
499  }
500  elseif($custom_update)
501  {
502  $this->setCustomUpdatesCurrentVersion($nr);
503  }
504 
505  if (!$hotfix && !$custom_update)
506  {
507  $this->clearRunningStatus();
508  }
509  //$this->currentVersion = $ilias->getSetting("db_version");
510 
511  return true;
512 
513  }
514 
516  {
517  if ($this->fileVersion > $this->currentVersion)
518  return false;
519  else
520  return true;
521  }
522 
523  function getTables()
524  {
525  $a = array();
526 
527  $query = "SHOW TABLES";
528  $res = $this->db->query($query);
529  while ($row = $res->fetchRow())
530  {
531  $status = $this->getTableStatus($row[0]);
532  $a[] = array(
533  "name" => $status["Table"],
534  "table" => $row[0],
535  "status" => $status["Msg_text"]
536  );
537  }
538  return $a;
539  }
540 
541  function getTableStatus($table)
542  {
543  $a = array();
544 
545  $query = "ANALYZE TABLE ".$table;
546  $res = $this->db->query($query);
547  $row = $res->fetchRow(DB_FETCHMODE_ASSOC);
548  return $row;
549  }
550 
551  function optimizeTables($tables)
552  {
553  $msg = array();
554  foreach ($_POST["tables"] as $key => $value)
555  {
556  $query = "OPTIMIZE TABLE ".$key;
557  $res = $this->db->query($query);
558  $msg[] = "table $key: ok";
559  }
560  return $msg;
561  }
562 
566 
567 
572  {
573  $this->readHotfixInfo();
574  return $this->hotfix_current_version;
575  }
576 
580  function setHotfixCurrentVersion($a_version)
581  {
582  $this->readHotfixInfo();
583  $this->hotfix_setting->set("db_hotfixes_".
584  $this->hotfix_version[0]."_".$this->hotfix_version[1], $a_version);
585  $this->hotfix_current_version = $a_version;
586  return true;
587  }
588 
593  {
594  $this->readHotfixInfo();
595  return $this->hotfix_file_version;
596  }
597 
601  function readHotfixFileVersion($a_file_content)
602  {
603  //go through filecontent and search for last occurence of <#x>
604  reset($a_file_content);
605  $regs = array();
606  foreach ($a_file_content as $row)
607  {
608  if (ereg("^<#([0-9]+)>", $row, $regs))
609  {
610  $version = $regs[1];
611  }
612  }
613 
614  return (integer) $version;
615  }
616 
620  function readHotfixInfo($a_force = false)
621  {
622  if ($this->hotfix_info_read && !$a_force)
623  {
624  return;
625  }
626  include_once './Services/Administration/classes/class.ilSetting.php';
627  $GLOBALS["ilDB"] = $this->db;
628  $this->hotfix_setting = new ilSetting("common", true);
629  $ilias_version = ILIAS_VERSION_NUMERIC;
630  $version_array = explode(".", $ilias_version);
631  $this->hotfix_version[0] = $version_array[0];
632  $this->hotfix_version[1] = $version_array[1];
633  $hotfix_file = $this->PATH."setup/sql/".$this->hotfix_version[0]."_".$this->hotfix_version[1]."_hotfixes.php";
634  if (is_file($hotfix_file))
635  {
636  $this->hotfix_content = @file($hotfix_file);
637  $this->hotfix_current_version = (int) $this->hotfix_setting->get("db_hotfixes_".
638  $this->hotfix_version[0]."_".$this->hotfix_version[1]);
639  $this->hotfix_file_version = $this->readHotfixFileVersion($this->hotfix_content);
640  }
641  $this->hotfix_info_read = true;
642  }
643 
647  function hotfixAvailable()
648  {
649  $this->readHotfixInfo();
650  if ($this->hotfix_file_version > $this->hotfix_current_version)
651  {
652  return true;
653  }
654  return false;
655  }
656 
660  function applyHotfix()
661  {
662  global $ilCtrlStructureReader, $ilMySQLAbstraction;
663 
664  include_once './Services/Database/classes/class.ilMySQLAbstraction.php';
665 
666  $ilMySQLAbstraction = new ilMySQLAbstraction();
667  $GLOBALS['ilMySQLAbstraction'] = $ilMySQLAbstraction;
668 
669  $this->readHotfixInfo(true);
670 
671  $f = $this->getHotfixFileVersion();
672  $c = $this->getHotfixCurrentVersion();
673 
674  if ($c < $f)
675  {
676  $msg = array();
677  for ($i=($c+1); $i<=$f; $i++)
678  {
679 // $this->initStep($i); // nothings happens here
680 
681  $this->filecontent = $this->hotfix_content;
682 
683  if ($this->applyUpdateNr($i, true) == false)
684  {
685  $msg[] = array(
686  "msg" => "update_error: ".$this->error,
687  "nr" => $i
688  );
689  $this->updateMsg = $msg;
690  return false;
691  }
692  else
693  {
694  $msg[] = array(
695  "msg" => "hotfix_applied",
696  "nr" => $i
697  );
698  }
699  }
700 
701  $this->updateMsg = $msg;
702  }
703  else
704  {
705  $this->updateMsg = "no_changes";
706  }
707 
708  return $this->loadXMLInfo();
709  }
710 
712  {
713  $this->readCustomUpdatesInfo();
714  return $this->custom_updates_current_version;
715  }
716 
717  public function setCustomUpdatesCurrentVersion($a_version)
718  {
719  $this->readCustomUpdatesInfo();
720  $this->custom_updates_setting->set('db_version_custom', $a_version);
721  $this->custom_updates_current_version = $a_version;
722  return true;
723  }
724 
725  public function getCustomUpdatesFileVersion()
726  {
727  $this->readCustomUpdatesInfo();
728  return $this->custom_updates_file_version;
729  }
730 
731  public function readCustomUpdatesFileVersion($a_file_content)
732  {
733  //go through filecontent and search for last occurence of <#x>
734  reset($a_file_content);
735  $regs = array();
736  foreach ($a_file_content as $row)
737  {
738  if (ereg("^<#([0-9]+)>", $row, $regs))
739  {
740  $version = $regs[1];
741  }
742  }
743 
744  return (integer) $version;
745  }
746 
747  public function readCustomUpdatesInfo($a_force = false)
748  {
749  if ($this->custom_updates_info_read && !$a_force)
750  {
751  return;
752  }
753  include_once './Services/Administration/classes/class.ilSetting.php';
754  $GLOBALS["ilDB"] = $this->db;
755  $this->custom_updates_setting = new ilSetting();
756  $custom_updates_file = $this->PATH."setup/sql/dbupdate_custom.php";
757  if (is_file($custom_updates_file))
758  {
759  $this->custom_updates_content = @file($custom_updates_file);
760  $this->custom_updates_current_version = (int) $this->custom_updates_setting->get('db_version_custom', 0);
761  $this->custom_updates_file_version = $this->readCustomUpdatesFileVersion($this->custom_updates_content);
762  }
763  $this->custom_updates_info_read = true;
764  }
765 
766  public function customUpdatesAvailable()
767  {
768  // trunk does not support custom updates
769  return false;
770 
771  $this->readCustomUpdatesInfo();
772  if ($this->custom_updates_file_version > $this->custom_updates_current_version)
773  {
774  return true;
775  }
776  return false;
777  }
778 
779  public function applyCustomUpdates()
780  {
781  global $ilCtrlStructureReader, $ilMySQLAbstraction;
782 
783  include_once './Services/Database/classes/class.ilMySQLAbstraction.php';
784 
785  $ilMySQLAbstraction = new ilMySQLAbstraction();
786  $GLOBALS['ilMySQLAbstraction'] = $ilMySQLAbstraction;
787 
788  $this->readCustomUpdatesInfo(true);
789 
790  $f = $this->getCustomUpdatesFileVersion();
791  $c = $this->getCustomUpdatesCurrentVersion();
792 
793  if ($c < $f)
794  {
795  $msg = array();
796  for ($i=($c+1); $i<=$f; $i++)
797  {
798 // $this->initStep($i); // nothings happens here
799 
800  $this->filecontent = $this->custom_updates_content;
801 
802  if ($this->applyUpdateNr($i, false, true) == false)
803  {
804  $msg[] = array(
805  "msg" => "update_error: ".$this->error,
806  "nr" => $i
807  );
808  $this->updateMsg = $msg;
809  return false;
810  }
811  else
812  {
813  $msg[] = array(
814  "msg" => "custom_update_applied",
815  "nr" => $i
816  );
817  }
818  }
819 
820  $this->updateMsg = $msg;
821  }
822  else
823  {
824  $this->updateMsg = "no_changes";
825  }
826 
827  return $this->loadXMLInfo();
828  }
829 
835  function getUpdateSteps($a_break = 0)
836  {
837  global $ilCtrlStructureReader, $ilMySQLAbstraction;
838 
839  $str = "";
840 
841  $f = $this->fileVersion;
843 
844  if ($a_break > $this->currentVersion &&
845  $a_break < $this->fileVersion)
846  {
847  $f = $a_break;
848  }
849 
850  if ($c < $f)
851  {
852  $msg = array();
853  for ($i=($c+1); $i<=$f; $i++)
854  {
855  // check wether next update file must be loaded
856  if ($this->current_file != $this->getFileForStep($i))
857  {
858  $this->DB_UPDATE_FILE = $this->PATH."setup/sql/".$this->getFileForStep($i);
859  $this->readDBUpdateFile();
860  }
861 
862  $str.= $this->getUpdateStepNr($i);
863  }
864 
865  }
866  return $str;
867  }
868 
874  function getHotfixSteps()
875  {
876  $this->readHotfixInfo(true);
877 
878  $str = "";
879 
880  $f = $this->getHotfixFileVersion();
881  $c = $this->getHotfixCurrentVersion();
882 
883  if ($c < $f)
884  {
885  $msg = array();
886  for ($i=($c+1); $i<=$f; $i++)
887  {
888  $this->filecontent = $this->hotfix_content;
889 
890  $str.= $this->getUpdateStepNr($i, true);
891  }
892  }
893 
894  return $str;
895  }
896 
897 
901  function getUpdateStepNr($nr, $hotfix = false, $custom_update = false)
902  {
903  global $ilDB,$ilErr,$ilUser,$ilCtrlStructureReader,$ilModuleReader,$ilMySQLAbstraction;
904 
905  $str = "";
906 
907  //search for desired $nr
908  reset($this->filecontent);
909 
910  //init
911  $i = 0;
912 
913  //go through filecontent
914  while (!ereg("^<#".$nr.">", $this->filecontent[$i]) && $i<count($this->filecontent))
915  {
916  $i++;
917  }
918 
919  //update not found
920  if ($i == count($this->filecontent))
921  {
922  return false;
923  }
924 
925  $i++;
926 
927  //update found, now extract this update to a new array
928  $update = array();
929  while ($i<count($this->filecontent) && !ereg("^<#".($nr+1).">", $this->filecontent[$i]))
930  {
931  $str.= $this->filecontent[$i];
932  $i++;
933  }
934 
935  return "<pre><b><#".$nr."></b>\n".htmlentities($str)."</pre>";
936  }
937 
938 } // END class.DBUdate
939 ?>