ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
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{
14
34 public $updateMsg;
35
36
43 public function __construct($a_db_handler = 0, $client_ini = null)
44 {
45 // workaround to allow setup migration
46 $this->client_ini = $client_ini;
47 if ($a_db_handler) {
48 $this->db = &$a_db_handler;
49 $this->PATH = "./";
50 } else {
51 global $DIC;
52 if ($DIC->offsetExists('mySetup')) {
53 $mySetup = $DIC['mySetup'];
54 }
55 $this->db = $mySetup->db;
56 $this->PATH = "./";
57 }
58
59 $this->getCurrentVersion();
60
61 // get update file for current version
62 $updatefile = $this->getFileForStep($this->currentVersion + 1);
63
64 $this->current_file = $updatefile;
65 $this->DB_UPDATE_FILE = $this->PATH . "setup/sql/" . $updatefile;
66
67 //
68 // NOTE: IF YOU SET THIS TO THE NEWEST FILE, CHANGE ALSO getFileForStep()
69 //
70 $this->LAST_UPDATE_FILE = $this->PATH . "setup/sql/dbupdate_05.php";
71
72 $this->readDBUpdateFile();
73 $this->readLastUpdateFile();
74 $this->readFileVersion();
75 }
76
77
85 public function getFileForStep($a_version)
86 {
87 //
88 // NOTE: IF YOU ADD A NEW FILE HERE, CHANGE ALSO THE CONSTRUCTOR
89 //
90 switch (true) {
91 case ((int) $a_version > 5431): // last number in previous file
92 return "dbupdate_05.php";
93 case ((int) $a_version > 4182): // last number in previous file
94 return "dbupdate_04.php";
95 case ((int) $a_version > 2948): // last number in previous file
96 return "dbupdate_03.php";
97 case ((int) $a_version > 864): // last number in previous file
98 return "dbupdate_02.php";
99 default:
100 return "dbupdate.php";
101 }
102 }
103
104
108 public function initStep($i)
109 {
110 //
111 }
112
113
114 public function readDBUpdateFile()
115 {
116 if (!file_exists($this->DB_UPDATE_FILE)) {
117 $this->error = "no_db_update_file";
118 $this->filecontent = array();
119
120 return false;
121 }
122
123 $this->filecontent = @file($this->DB_UPDATE_FILE);
124
125 return true;
126 }
127
128
129 public function readLastUpdateFile()
130 {
131 if (!file_exists($this->LAST_UPDATE_FILE)) {
132 $this->error = "no_last_update_file";
133 $this->lastfilecontent = array();
134
135 return false;
136 }
137
138 $this->lastfilecontent = @file($this->LAST_UPDATE_FILE);
139
140 return true;
141 }
142
143
147 public function getCurrentVersion()
148 {
149 $set = new ilSetting("common", true);
150 $this->currentVersion = (integer) $set->get("db_version");
151
153 }
154
155
161 public function setCurrentVersion($a_version)
162 {
163 $set = new ilSetting("common", true);
164 $set->set("db_version", $a_version);
165 $this->currentVersion = $a_version;
166
167 return true;
168 }
169
170
176 public function setRunningStatus($a_nr)
177 {
178 $set = new ilSetting("common", true);
179 $set->set("db_update_running", $a_nr);
180 $this->db_update_running = $a_nr;
181 }
182
183
189 public function getRunningStatus()
190 {
191 $set = new ilSetting("common", true);
192 $this->db_update_running = (integer) $set->get("db_update_running");
193
194 return $this->db_update_running;
195 }
196
197
201 public function clearRunningStatus()
202 {
203 $set = new ilSetting("common", true);
204 $set->set("db_update_running", 0);
205 $this->db_update_running = 0;
206 }
207
208
209 public function readFileVersion()
210 {
211 //go through filecontent and search for last occurence of <#x>
212 reset($this->lastfilecontent);
213 $regs = array();
214 foreach ($this->lastfilecontent as $row) {
215 if (preg_match('/^<\#([0-9]+)>/', $row, $regs)) {
216 $version = $regs[1];
217 }
218 }
219
220 $this->fileVersion = (integer) $version;
221
222 return $this->fileVersion;
223 }
224
225
229 public function getFileVersion()
230 {
231 return $this->fileVersion;
232 }
233
234
243 public function execQuery($db, $str)
244 {
245 $sql = explode("\n", trim($str));
246 for ($i = 0; $i < count($sql); $i++) {
247 $sql[$i] = trim($sql[$i]);
248 if ($sql[$i] != "" && substr($sql[$i], 0, 1) != "#") {
249 //take line per line, until last char is ";"
250 if (substr($sql[$i], -1) == ";") {
251 //query is complete
252 $q .= " " . substr($sql[$i], 0, -1);
253 $check = $this->checkQuery($q);
254 if ($check === true) {
255 try {
256 $r = $db->query($q);
257 } catch (ilDatabaseException $e) {
258 var_dump($e); // FSX
259 exit;
260 $this->error = $e->getMessage();
261
262 return false;
263 }
264 } else {
265 $this->error = $check;
266
267 return false;
268 }
269 unset($q);
270 } //if
271 else {
272 $q .= " " . $sql[$i];
273 } //else
274 } //if
275 } //for
276 if (isset($q) && $q != "") {
277 echo "incomplete_statement: " . $q . "<br>";
278
279 return false;
280 }
281
282 return true;
283 }
284
285
289 public function checkQuery($q)
290 {
291 return true;
292 }
293
294
300 private function initGlobalsRequiredForUpdateSteps(&$ilCtrlStructureReader, &$ilMySQLAbstraction, &$ilDB)
301 {
302 global $DIC;
303
304 // TODO: There is currently a huge mixup of globals, $DIC and dependencies, esprecially in setup and during DB-Updates. This leads to many problems. The following core tries to provide the needed dependencies for the dbupdate-script. The code hopefully will change in the future.
305
306 if (isset($GLOBALS['ilCtrlStructureReader'])) {
307 $ilCtrlStructureReader = $GLOBALS['ilCtrlStructureReader'];
308 } elseif ($DIC->offsetExists('ilCtrlStructureReader')) {
309 $ilCtrlStructureReader = $DIC['ilCtrlStructureReader'];
310 } else {
312 $DIC->offsetSet('ilCtrlStructureReader', $ilCtrlStructureReader);
313 }
314
315 $GLOBALS['ilCtrlStructureReader'] = $ilCtrlStructureReader;
316
317 if ($DIC->offsetExists('ilMySQLAbstraction')) {
318 $ilMySQLAbstraction = $DIC['ilMySQLAbstraction'];
319 } else {
320 $ilMySQLAbstraction = new ilMySQLAbstraction();
321 $DIC->offsetSet('ilMySQLAbstraction', $ilMySQLAbstraction);
322 }
323
324 $GLOBALS['ilMySQLAbstraction'] = $ilMySQLAbstraction;
325
326 if ($this->client_ini) {
327 $ilCtrlStructureReader->setIniFile($this->client_ini);
328 }
329 $ilDB = $DIC->database();
330 }
331
332
336 public function applyUpdate($a_break = 0)
337 {
339 $ilMySQLAbstraction = null;
340 $ilDB = null;
342
345
346 if ($a_break > $this->currentVersion
347 && $a_break < $this->fileVersion
348 ) {
349 $f = $a_break;
350 }
351
352 if ($c < $f) {
353 $msg = array();
354 for ($i = ($c + 1); $i <= $f; $i++) {
355 // check wether next update file must be loaded
356 if ($this->current_file != $this->getFileForStep($i)) {
357 $this->DB_UPDATE_FILE = $this->PATH . "setup/sql/" . $this->getFileForStep($i);
358 $this->readDBUpdateFile();
359 }
360
361 $this->initStep($i);
362
363 if ($this->applyUpdateNr($i) == false) {
364 $msg[] = array("msg" => "update_error: " . $this->error,
365 "nr" => $i,);
366 $this->updateMsg = $msg;
367
368 return false;
369 } else {
370 $msg[] = array("msg" => "update_applied",
371 "nr" => $i,);
372 }
373 }
374
375 $this->updateMsg = $msg;
376 } else {
377 $this->updateMsg = "no_changes";
378 }
379
380 if ($f < $this->fileVersion) {
381 return true;
382 } else {
383 return $this->loadXMLInfo();
384 }
385 }
386
387
388 public function loadXMLInfo()
389 {
391 $ilMySQLAbstraction = null;
392 $ilDB = null;
394
395 // read module and service information into db
398
399 $ilCtrlStructureReader->readStructure();
400
401 $mr = new ilModuleReader("", "", "");
402 $mr->clearTables();
403 foreach ($modules as $module) {
404 $mr = new ilModuleReader(
405 ILIAS_ABSOLUTE_PATH . "/Modules/" . $module["subdir"] . "/module.xml",
406 $module["subdir"],
407 "Modules"
408 );
409 $mr->getModules();
410 unset($mr);
411 }
412
413 $sr = new ilServiceReader("", "", "");
414 $sr->clearTables();
415 foreach ($services as $service) {
416 $sr = new ilServiceReader(
417 ILIAS_ABSOLUTE_PATH . "/Services/" . $service["subdir"] . "/service.xml",
418 $service["subdir"],
419 "Services"
420 );
421 $sr->getServices();
422 unset($sr);
423 }
424
425
426
427 return true;
428 }
429
430
439 public function applyUpdateNr(&$nr, $hotfix = false, $custom_update = false)
440 {
442 $ilMySQLAbstraction = null;
443 $ilDB = null;
445
446 //search for desired $nr
447 reset($this->filecontent);
448
449 if (!$hotfix && !$custom_update) {
450 $this->setRunningStatus($nr);
451 }
452
453 //init
454 $i = 0;
455
456 //go through filecontent
457 while (!preg_match("/^<\#" . $nr . ">/", $this->filecontent[$i]) && $i < count($this->filecontent)) {
458 $i++;
459 }
460
461 //update not found
462 if ($i == count($this->filecontent)) {
463 $this->error = "update_not_found";
464
465 return false;
466 }
467
468 $i++;
469
470 //update found, now extract this update to a new array
471 $update = array();
472 while ($i < count($this->filecontent) && !preg_match("/^<#" . ($nr + 1) . ">/", $this->filecontent[$i])) {
473 $update[] = trim($this->filecontent[$i]);
474 $i++;
475 }
476
477 //now you have the update, now process it
478 $sql = array();
479 $php = array();
480 $mode = "sql";
481
482 foreach ($update as $row) {
483 if (preg_match("/<\?php/", $row)) {
484 if (count($sql) > 0) {
485 if ($this->execQuery($this->db, implode("\n", $sql)) == false) {
486 $this->error = $this->error;
487
488 return false;
489 }
490 $sql = array();
491 }
492 $mode = "php";
493 } elseif (preg_match("/\?>/", $row)) {
494 if (count($php) > 0) {
495 $code = implode("\n", $php);
496 if (eval($code) === false) {
497 $this->error = "Parse error: " . $code;
498
499 return false;
500 }
501 $php = array();
502 }
503 $mode = "sql";
504 } else {
505 if ($mode == "sql") {
506 $sql[] = $row;
507 }
508
509 if ($mode == "php") {
510 $php[] = $row;
511 }
512 } //else
513 } //foreach
514
515 if ($mode == "sql" && count($sql) > 0) {
516 if ($this->execQuery($this->db, implode("\n", $sql)) == false) {
517 $this->error = "dump_error: " . $this->error;
518
519 return false;
520 }
521 }
522
523 //increase db_Version number
524 if (!$hotfix && !$custom_update) {
525 $this->setCurrentVersion($nr);
526 } elseif ($hotfix) {
527 $this->setHotfixCurrentVersion($nr);
528 } elseif ($custom_update) {
530 }
531
532 if (!$hotfix && !$custom_update) {
533 $this->clearRunningStatus();
534 }
535
536 //$this->currentVersion = $ilias->getSetting("db_version");
537
538 return true;
539 }
540
541
542 public function getDBVersionStatus()
543 {
544 if ($this->fileVersion > $this->currentVersion) {
545 return false;
546 } else {
547 return true;
548 }
549 }
550
551
552 public function getTables()
553 {
554 $a = array();
555
556 $query = "SHOW TABLES";
557 $res = $this->db->query($query);
558 while ($row = $res->fetchRow()) {
559 $status = $this->getTableStatus($row[0]);
560 $a[] = array("name" => $status["Table"],
561 "table" => $row[0],
562 "status" => $status["Msg_text"],);
563 }
564
565 return $a;
566 }
567
568
569 public function getTableStatus($table)
570 {
571 $a = array();
572
573 $query = "ANALYZE TABLE " . $table;
574 $res = $this->db->query($query);
575 $row = $res->fetchRow(ilDBConstants::FETCHMODE_ASSOC);
576
577 return $row;
578 }
579
580
584
588 public function getHotfixCurrentVersion()
589 {
590 $this->readHotfixInfo();
591
592 return $this->hotfix_current_version ?? null;
593 }
594
595
599 public function setHotfixCurrentVersion($a_version)
600 {
601 $this->readHotfixInfo();
602 $this->hotfix_setting->set(
603 "db_hotfixes_" . $this->hotfix_version[0],
604 $a_version
605 );
606 $this->hotfix_current_version = $a_version;
607
608 return true;
609 }
610
611
615 public function getHotfixFileVersion()
616 {
617 $this->readHotfixInfo();
618
619 return $this->hotfix_file_version ?? null;
620 }
621
622
626 public function readHotfixFileVersion($a_file_content)
627 {
628 //go through filecontent and search for last occurence of <#x>
629 reset($a_file_content);
630 $regs = array();
631 foreach ($a_file_content as $row) {
632 if (preg_match("/^<#([0-9]+)>/", $row, $regs)) {
633 $version = $regs[1];
634 }
635 }
636
637 return (integer) $version;
638 }
639
640
644 public function readHotfixInfo($a_force = false)
645 {
646 if (isset($this->hotfix_info_read) && $this->hotfix_info_read && !$a_force) {
647 return;
648 }
649 $this->hotfix_setting = new ilSetting("common", true);
650 $ilias_version = ILIAS_VERSION_NUMERIC;
651 $version_array = explode(".", $ilias_version);
652 $this->hotfix_version[0] = $version_array[0];
653 $this->hotfix_version[1] = $version_array[1];
654 $hotfix_file = $this->PATH . "setup/sql/" . $this->hotfix_version[0] . "_hotfixes.php";
655 if (is_file($hotfix_file)) {
656 $this->hotfix_content = @file($hotfix_file);
657 $this->hotfix_current_version = (int) $this->hotfix_setting->get(
658 "db_hotfixes_" . $this->hotfix_version[0]
659 );
660 $this->hotfix_file_version = $this->readHotfixFileVersion($this->hotfix_content);
661 }
662 $this->hotfix_info_read = true;
663 }
664
665
669 public function hotfixAvailable()
670 {
671 $this->readHotfixInfo();
672 if (isset($this->hotfix_file_version) && $this->hotfix_file_version > $this->hotfix_current_version) {
673 return true;
674 }
675
676 return false;
677 }
678
679
683 public function applyHotfix()
684 {
686 $ilMySQLAbstraction = null;
687 $ilDB = null;
689
690 $ilMySQLAbstraction = new ilMySQLAbstraction();
691 $GLOBALS['DIC']['ilMySQLAbstraction'] = $ilMySQLAbstraction;
692
693 $this->readHotfixInfo(true);
694
695 $f = $this->getHotfixFileVersion();
696 $c = $this->getHotfixCurrentVersion();
697
698 if ($c < $f) {
699 $msg = array();
700 for ($i = ($c + 1); $i <= $f; $i++) {
701 // $this->initStep($i); // nothings happens here
702
703 $this->filecontent = $this->hotfix_content;
704
705 if ($this->applyUpdateNr($i, true) == false) {
706 $msg[] = array("msg" => "update_error: " . $this->error,
707 "nr" => $i,);
708 $this->updateMsg = $msg;
709
710 return false;
711 } else {
712 $msg[] = array("msg" => "hotfix_applied",
713 "nr" => $i,);
714 }
715 }
716
717 $this->updateMsg = $msg;
718 } else {
719 $this->updateMsg = "no_changes";
720 }
721
722 return $this->loadXMLInfo();
723 }
724
725
727 {
728 $this->readCustomUpdatesInfo();
729
730 return $this->custom_updates_current_version;
731 }
732
733
734 public function setCustomUpdatesCurrentVersion($a_version)
735 {
736 $this->readCustomUpdatesInfo();
737 $this->custom_updates_setting->set('db_version_custom', $a_version);
738 $this->custom_updates_current_version = $a_version;
739
740 return true;
741 }
742
743
745 {
746 $this->readCustomUpdatesInfo();
747
748 return $this->custom_updates_file_version;
749 }
750
751
752 public function readCustomUpdatesFileVersion($a_file_content)
753 {
754 //go through filecontent and search for last occurence of <#x>
755 reset($a_file_content);
756 $regs = array();
757 foreach ($a_file_content as $row) {
758 if (preg_match("/^<#([0-9]+)>/", $row, $regs)) {
759 $version = $regs[1];
760 }
761 }
762
763 return (integer) $version;
764 }
765
766
767 public function readCustomUpdatesInfo($a_force = false)
768 {
769 if ($this->custom_updates_info_read && !$a_force) {
770 return;
771 }
772
773 $this->custom_updates_setting = new ilSetting();
774 $custom_updates_file = $this->PATH . "setup/sql/dbupdate_custom.php";
775 if (is_file($custom_updates_file)) {
776 $this->custom_updates_content = @file($custom_updates_file);
777 $this->custom_updates_current_version = (int) $this->custom_updates_setting->get('db_version_custom', 0);
778 $this->custom_updates_file_version = $this->readCustomUpdatesFileVersion($this->custom_updates_content);
779 }
780 $this->custom_updates_info_read = true;
781 }
782
783
784 public function customUpdatesAvailable()
785 {
786 // trunk does not support custom updates
787 // return false;
788
789 $this->readCustomUpdatesInfo();
790 if ($this->custom_updates_file_version > $this->custom_updates_current_version) {
791 return true;
792 }
793
794 return false;
795 }
796
797
798 public function applyCustomUpdates()
799 {
801 $ilMySQLAbstraction = null;
802 $ilDB = null;
804
805 $ilMySQLAbstraction = new ilMySQLAbstraction();
806 $GLOBALS['DIC']['ilMySQLAbstraction'] = $ilMySQLAbstraction;
807
808 $this->readCustomUpdatesInfo(true);
809
812
813 if ($c < $f) {
814 $msg = array();
815 for ($i = ($c + 1); $i <= $f; $i++) {
816 $this->filecontent = $this->custom_updates_content;
817
818 if ($this->applyUpdateNr($i, false, true) == false) {
819 $msg[] = array("msg" => "update_error: " . $this->error,
820 "nr" => $i,);
821 $this->updateMsg = $msg;
822
823 return false;
824 } else {
825 $msg[] = array("msg" => "custom_update_applied",
826 "nr" => $i,);
827 }
828 }
829
830 $this->updateMsg = $msg;
831 } else {
832 $this->updateMsg = "no_changes";
833 }
834
835 return $this->loadXMLInfo();
836 }
837
838
844 public function getUpdateSteps($a_break = 0)
845 {
847 $ilMySQLAbstraction = null;
848 $ilDB = null;
850
851 $str = "";
852
855
856 if ($a_break > $this->currentVersion
857 && $a_break < $this->fileVersion
858 ) {
859 $f = $a_break;
860 }
861
862 if ($c < $f) {
863 $msg = array();
864 for ($i = ($c + 1); $i <= $f; $i++) {
865 // check wether next update file must be loaded
866 if ($this->current_file != $this->getFileForStep($i)) {
867 $this->DB_UPDATE_FILE = $this->PATH . "setup/sql/" . $this->getFileForStep($i);
868 $this->readDBUpdateFile();
869 }
870
871 $str .= $this->getUpdateStepNr($i);
872 }
873 }
874
875 return $str;
876 }
877
878
884 public function getHotfixSteps()
885 {
886 $this->readHotfixInfo(true);
887
888 $str = "";
889
890 $f = $this->getHotfixFileVersion();
891 $c = $this->getHotfixCurrentVersion();
892
893 if ($c < $f) {
894 $msg = array();
895 for ($i = ($c + 1); $i <= $f; $i++) {
896 $this->filecontent = $this->hotfix_content;
897
898 $str .= $this->getUpdateStepNr($i, true);
899 }
900 }
901
902 return $str;
903 }
904
905
909 public function getUpdateStepNr($nr, $hotfix = false, $custom_update = false)
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 (!preg_match("/^<#" . $nr . ">/", $this->filecontent[$i]) && $i < count($this->filecontent)) {
921 $i++;
922 }
923
924 //update not found
925 if ($i == count($this->filecontent)) {
926 return false;
927 }
928
929 $i++;
930
931 //update found, now extract this update to a new array
932 $update = array();
933 while ($i < count($this->filecontent) && !preg_match("/^<#" . ($nr + 1) . ">/", $this->filecontent[$i])) {
934 $str .= $this->filecontent[$i];
935 $i++;
936 }
937
938 return "<pre><b><#" . $nr . "></b>\n" . htmlentities($str) . "</pre>";
939 }
940}
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
Definition: PEAR.php:64
An exception for terminatinating execution or to throw for unit testing.
error($a_errmsg)
set error message @access public
Class ilCtrlStructureReader.
Database Update class.
getUpdateStepNr($nr, $hotfix=false, $custom_update=false)
Get single update step for presentation.
getFileVersion()
Get Version of file.
applyUpdate($a_break=0)
Apply update.
readCustomUpdatesInfo($a_force=false)
__construct($a_db_handler=0, $client_ini=null)
ilDBUpdate constructor.
$DB_UPDATE_FILE
db update file
getHotfixSteps()
Get hotfix steps.
setCurrentVersion($a_version)
getFileForStep($a_version)
Get db update file name for db step.
getUpdateSteps($a_break=0)
Get update steps as string (for presentation)
setRunningStatus($a_nr)
Set running status for a step.
getCustomUpdatesCurrentVersion()
setHotfixCurrentVersion($a_version)
Set current hotfix version.
initGlobalsRequiredForUpdateSteps(&$ilCtrlStructureReader, &$ilMySQLAbstraction, &$ilDB)
execQuery($db, $str)
execute a query
checkQuery($q)
check query
getHotfixCurrentVersion()
Get current hotfix version.
getHotfixFileVersion()
Get current hotfix version.
readHotfixInfo($a_force=false)
Get status of hotfix file.
readCustomUpdatesFileVersion($a_file_content)
hotfixAvailable()
Get status of hotfix file.
setCustomUpdatesCurrentVersion($a_version)
applyUpdateNr(&$nr, $hotfix=false, $custom_update=false)
apply an update
getTableStatus($table)
clearRunningStatus()
Clear running status.
applyHotfix()
Apply hotfix.
getRunningStatus()
Get running status.
readHotfixFileVersion($a_file_content)
Set current hotfix version.
Class ilDatabaseException.
Class ilModuleReader.
static getAvailableCoreModules()
Get all available core modules.
This class includes methods that help to abstract ILIAS 3.10.x MySQL tables for the use with MDB2 abs...
Class ilServiceReader.
static getAvailableCoreServices()
Get all available core services.
ILIAS Setting Class.
const ILIAS_VERSION_NUMERIC
$ilCtrlStructureReader
exit
Definition: login.php:29
$i
Definition: metadata.php:24
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
const PATH
Definition: proxy_ylocal.php:8
$query
$service
Definition: result.php:17
foreach($_POST as $key=> $value) $res
global $ilDB
$DIC
Definition: xapitoken.php:46