]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Core/Install.php
82e874fe30548aa0f602f96b9dbb0f499969d361
[galette.git] / galette / lib / Galette / Core / Install.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Galette installation
7 *
8 * PHP version 5
9 *
10 * Copyright © 2013-2023 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Core
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2013-2023 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
34 * @since Available since 0.8 - 2013-01-09
35 */
36
37 namespace Galette\Core;
38
39 use Throwable;
40 use Analog\Analog;
41 use Laminas\Db\Adapter\Adapter;
42
43 /**
44 * Galette installation
45 *
46 * @category Core
47 * @name Install
48 * @package Galette
49 * @author Johan Cwiklinski <johan@x-tnd.be>
50 * @copyright 2013-2023 The Galette Team
51 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
52 * @link http://galette.tuxfamily.org
53 * @since Available since 0.8 - 2013-01-09
54 */
55 class Install
56 {
57 public const STEP_CHECK = 0;
58 public const STEP_TYPE = 1;
59 public const STEP_DB = 2;
60 public const STEP_DB_CHECKS = 3;
61 public const STEP_VERSION = 4; //only for update
62 public const STEP_DB_UPGRADE = 5;
63 public const STEP_DB_INSTALL = 6;
64 public const STEP_ADMIN = 7;
65 public const STEP_GALETTE_INIT = 8;
66 public const STEP_END = 9;
67
68 public const INSTALL = 'i';
69 public const UPDATE = 'u';
70
71 //db version/galette version mapper
72 private $versions_mapper = array(
73 '0.700' => '0.70',
74 '0.701' => '0.71',
75 '0.702' => '0.74',
76 '0.703' => '0.75',
77 '0.704' => '0.76'
78 );
79
80 protected $_step;
81 private $_mode;
82 private $_version;
83 private $_installed_version;
84
85 private $_db_type;
86 private $_db_host;
87 private $_db_port;
88 private $_db_name;
89 private $_db_user;
90 private $_db_pass;
91 private $_db_prefix;
92
93 private $_db_connected;
94 private $_report;
95
96 private $_admin_login;
97 private $_admin_pass;
98
99 private $_error;
100
101 /**
102 * Main constructor
103 */
104 public function __construct()
105 {
106 $this->_step = self::STEP_CHECK;
107 $this->_mode = null;
108 $this->_version = str_replace('v', '', GALETTE_VERSION);
109 $this->_db_connected = false;
110 $this->_db_prefix = null;
111 }
112
113 /**
114 * Return current step title
115 *
116 * @return string
117 */
118 public function getStepTitle()
119 {
120 $step_title = null;
121 switch ($this->_step) {
122 case self::STEP_CHECK:
123 $step_title = _T("Checks");
124 break;
125 case self::STEP_TYPE:
126 $step_title = _T("Installation mode");
127 break;
128 case self::STEP_DB:
129 $step_title = _T("Database");
130 break;
131 case self::STEP_DB_CHECKS:
132 $step_title = _T("Database access and permissions");
133 break;
134 case self::STEP_VERSION:
135 $step_title = _T("Previous version selection");
136 break;
137 case self::STEP_DB_UPGRADE:
138 $step_title = _T("Datapase upgrade");
139 break;
140 case self::STEP_DB_INSTALL:
141 $step_title = _T("Tables Creation");
142 break;
143 case self::STEP_ADMIN:
144 $step_title = _T("Admin parameters");
145 break;
146 case self::STEP_GALETTE_INIT:
147 $step_title = _T("Galette initialization");
148 break;
149 case self::STEP_END:
150 $step_title = _T("End!");
151 break;
152 }
153 return $step_title;
154 }
155
156 /**
157 * HTML validation image
158 *
159 * @param bool $arg Argument
160 *
161 * @return string html string
162 */
163 public function getValidationImage($arg)
164 {
165 $img_name = ($arg === true) ? 'green check' : 'red times';
166 $alt = ($arg === true) ? _T("Ok") : _T("Ko");
167 $img = '<i class="ui ' . $img_name . ' icon"></i><span class="displaynone">' . $alt . '</span>';
168 return $img;
169 }
170
171 /**
172 * Get current mode
173 *
174 * @return string
175 */
176 public function getMode()
177 {
178 return $this->_mode;
179 }
180
181 /**
182 * Are we installing?
183 *
184 * @return boolean
185 */
186 public function isInstall()
187 {
188 return $this->_mode === self::INSTALL;
189 }
190
191 /**
192 * Are we upgrading?
193 *
194 * @return boolean
195 */
196 public function isUpgrade()
197 {
198 return $this->_mode === self::UPDATE;
199 }
200
201 /**
202 * Set installation mode
203 *
204 * @param string $mode Requested mode
205 *
206 * @return void
207 */
208 public function setMode($mode)
209 {
210 if ($mode === self::INSTALL || $mode === self::UPDATE) {
211 $this->_mode = $mode;
212 } else {
213 throw new \UnexpectedValueException('Unknown mode "' . $mode . '"');
214 }
215 }
216
217 /**
218 * Go back to previous step
219 *
220 * @return void
221 */
222 public function atPreviousStep()
223 {
224 if ($this->_step > 0) {
225 if (
226 $this->_step - 1 !== self::STEP_DB_INSTALL
227 && $this->_step !== self::STEP_END
228 ) {
229 if ($this->_step === self::STEP_DB_INSTALL) {
230 $this->_step = self::STEP_DB_CHECKS;
231 } else {
232 if ($this->_step === self::STEP_DB_UPGRADE) {
233 $this->setInstalledVersion(null);
234 }
235 $this->_step = $this->_step - 1;
236 }
237 } else {
238 $msg = null;
239 if ($this->_step === self::STEP_END) {
240 $msg = 'Ok man, install is finished already!';
241 } else {
242 $msg = 'It is forbidden to rerun database install!';
243 }
244 Analog::log($msg, Analog::WARNING);
245 }
246 }
247 }
248
249 /**
250 * Are we at check step?
251 *
252 * @return boolean
253 */
254 public function isCheckStep()
255 {
256 return $this->_step === self::STEP_CHECK;
257 }
258
259 /**
260 * Set step to type of installation
261 *
262 * @return void
263 */
264 public function atTypeStep()
265 {
266 $this->_step = self::STEP_TYPE;
267 }
268
269 /**
270 * Are we at type step?
271 *
272 * @return boolean
273 */
274 public function isTypeStep()
275 {
276 return $this->_step === self::STEP_TYPE;
277 }
278
279 /**
280 * Set step to database information
281 *
282 * @return void
283 */
284 public function atDbStep()
285 {
286 $this->_step = self::STEP_DB;
287 }
288
289 /**
290 * Are we at database step?
291 *
292 * @return boolean
293 */
294 public function isDbStep()
295 {
296 return $this->_step === self::STEP_DB;
297 }
298
299 /**
300 * Is DB step passed?
301 *
302 * @return boolean
303 */
304 public function postCheckDb()
305 {
306 return $this->_step > self::STEP_DB_CHECKS;
307 }
308
309 /**
310 * Set database type
311 *
312 * @param string $type Database type
313 * @param array $errs Errors array
314 *
315 * @return Install
316 */
317 public function setDbType($type, &$errs)
318 {
319 switch ($type) {
320 case Db::MYSQL:
321 case Db::PGSQL:
322 $this->_db_type = $type;
323 break;
324 default:
325 $errs[] = _T("Database type unknown");
326 }
327 return $this;
328 }
329
330 /**
331 * Get database type
332 *
333 * @return string
334 */
335 public function getDbType()
336 {
337 return $this->_db_type;
338 }
339
340 /**
341 * Set connection information
342 *
343 * @param string $host Database host
344 * @param string $port Database port
345 * @param string $name Database name
346 * @param string $user Database user name
347 * @param string $pass Database user's password
348 *
349 * @return void
350 */
351 public function setDsn($host, $port, $name, $user, $pass)
352 {
353 $this->_db_host = $host;
354 $this->_db_port = $port;
355 $this->_db_name = $name;
356 $this->_db_user = $user;
357 $this->_db_pass = $pass;
358 }
359
360 /**
361 * Set tables prefix
362 *
363 * @param string $prefix Prefix
364 *
365 * @return void
366 */
367 public function setTablesPrefix($prefix)
368 {
369 $this->_db_prefix = $prefix;
370 }
371
372 /**
373 * Retrieve database host
374 *
375 * @return string
376 */
377 public function getDbHost()
378 {
379 return $this->_db_host;
380 }
381
382 /**
383 * Retrieve database port
384 *
385 * @return string
386 */
387 public function getDbPort()
388 {
389 return $this->_db_port;
390 }
391
392 /**
393 * Retrieve database name
394 *
395 * @return string
396 */
397 public function getDbName()
398 {
399 return $this->_db_name;
400 }
401
402 /**
403 * Retrieve database user
404 *
405 * @return string
406 */
407 public function getDbUser()
408 {
409 return $this->_db_user;
410 }
411
412 /**
413 * Retrieve database password
414 *
415 * @return string
416 */
417 public function getDbPass()
418 {
419 return $this->_db_pass;
420 }
421
422 /**
423 * Retrieve tables prefix
424 *
425 * @return string
426 */
427 public function getTablesPrefix()
428 {
429 return $this->_db_prefix;
430 }
431
432 /**
433 * Set step to database checks
434 *
435 * @return void
436 */
437 public function atDbCheckStep()
438 {
439 $this->_step = self::STEP_DB_CHECKS;
440 }
441
442 /**
443 * Are we at database check step?
444 *
445 * @return boolean
446 */
447 public function isDbCheckStep()
448 {
449 return $this->_step === self::STEP_DB_CHECKS;
450 }
451
452 /**
453 * Test database connection
454 *
455 * @return true
456 *
457 * @throws \Exception
458 */
459 public function testDbConnexion()
460 {
461 return Db::testConnectivity(
462 $this->_db_type,
463 $this->_db_user,
464 $this->_db_pass,
465 $this->_db_host,
466 $this->_db_port,
467 $this->_db_name
468 );
469 }
470
471 /**
472 * Is database connexion ok?
473 *
474 * @return boolean
475 */
476 public function isDbConnected()
477 {
478 return $this->_db_connected;
479 }
480
481 /**
482 * Set step to version selection
483 *
484 * @return void
485 */
486 public function atVersionSelection()
487 {
488 $this->_step = self::STEP_VERSION;
489 }
490
491 /**
492 * Are we at version selection step?
493 *
494 * @return boolean
495 */
496 public function isVersionSelectionStep()
497 {
498 return $this->_step === self::STEP_VERSION;
499 }
500
501 /**
502 * Set step to database installation
503 *
504 * @return void
505 */
506 public function atDbInstallStep()
507 {
508 $this->_step = self::STEP_DB_INSTALL;
509 }
510
511 /**
512 * Are we at db installation step?
513 *
514 * @return boolean
515 */
516 public function isDbinstallStep()
517 {
518 return $this->_step === self::STEP_DB_INSTALL;
519 }
520
521 /**
522 * Set step to database upgrade
523 *
524 * @return void
525 */
526 public function atDbUpgradeStep()
527 {
528 $this->_step = self::STEP_DB_UPGRADE;
529 }
530
531 /**
532 * Are we at db upgrade step?
533 *
534 * @return boolean
535 */
536 public function isDbUpgradeStep()
537 {
538 return $this->_step === self::STEP_DB_UPGRADE;
539 }
540
541
542 /**
543 * Install/Update SQL scripts
544 *
545 * @param string $path Path to scripts (defaults to core scripts)
546 *
547 * @return array
548 */
549 public function getScripts($path = null)
550 {
551 if ($path === null) {
552 $path = GALETTE_ROOT . '/install';
553 }
554 $update_scripts = array();
555
556 if ($this->isUpgrade()) {
557 $update_scripts = self::getUpdateScripts(
558 $path,
559 $this->_db_type,
560 $this->_installed_version
561 );
562 } else {
563 $update_scripts['current'] = $this->_db_type . '.sql';
564 }
565
566 return $update_scripts;
567 }
568
569 /**
570 * List updates scripts from given path
571 *
572 * @param string $path Scripts path
573 * @param string $db_type Database type
574 * @param string $version Previous version, defaults to null
575 *
576 * @return array If a previous version is provided, update scripts
577 * file path from this one to the latest will be returned.
578 * If no previous version is provided, that will return all
579 * updates versions known.
580 */
581 public static function getUpdateScripts(
582 $path,
583 $db_type = 'mysql',
584 $version = null
585 ) {
586 $dh = opendir($path . '/scripts');
587 $php_update_scripts = array();
588 $sql_update_scripts = array();
589 $update_scripts = [];
590 if ($dh !== false) {
591 while (($file = readdir($dh)) !== false) {
592 if (preg_match("/upgrade-to-(.*).php/", $file, $ver)) {
593 if ($version === null) {
594 $php_update_scripts[$ver[1]] = $ver[1];
595 } else {
596 if ($version < $ver[1]) {
597 $php_update_scripts[$ver[1]] = $file;
598 }
599 }
600 }
601 if (
602 preg_match(
603 "/upgrade-to-(.*)-" . $db_type . ".sql/",
604 $file,
605 $ver
606 )
607 ) {
608 if ($version === null) {
609 $sql_update_scripts[$ver[1]] = $ver[1];
610 } else {
611 if ($version < $ver[1]) {
612 $sql_update_scripts[$ver[1]] = $file;
613 }
614 }
615 }
616 }
617 $update_scripts = array_merge($sql_update_scripts, $php_update_scripts);
618 closedir($dh);
619 ksort($update_scripts);
620 }
621 return $update_scripts;
622 }
623
624 /**
625 * Execute SQL scripts
626 *
627 * @param Db $zdb Database instance
628 * @param string $spath Path to scripts
629 *
630 * @return bool
631 */
632 public function executeScripts(Db $zdb, $spath = null)
633 {
634 $fatal_error = false;
635 $update_scripts = $this->getScripts($spath);
636 $this->_report = array();
637 $scripts_path = ($spath ?? GALETTE_ROOT . '/install') . '/scripts/';
638
639 foreach ($update_scripts as $key => $val) {
640 if (substr($val, -strlen('.sql')) === '.sql') {
641 //just a SQL script, run it
642 $script = fopen($scripts_path . $val, 'r');
643
644 if ($script === false) {
645 throw new \RuntimeException(
646 'Unable to read SQL script from ' . $scripts_path . $val
647 );
648 }
649
650 $sql_query = @fread(
651 $script,
652 @filesize($scripts_path . $val)
653 ) . "\n";
654
655 $sql_res = $this->executeSql($zdb, $sql_query);
656 if (!$sql_res) {
657 $fatal_error = true;
658 }
659 } else {
660 //we got an update class
661 include_once $scripts_path . $val;
662 $className = '\Galette\Updates\UpgradeTo' .
663 str_replace('.', '', $key);
664 $ret = array(
665 'message' => null,
666 'res' => false
667 );
668 try {
669 $updater = new $className();
670 if ($updater instanceof \Galette\Updater\AbstractUpdater) {
671 $updater->run($zdb, $this);
672 $ret = $updater->getReport();
673 $this->_report = array_merge($this->_report, $ret);
674 } else {
675 $fatal_error = true;
676 Analog::log(
677 'Update class does not extends AbstractUpdater!',
678 Analog::ERROR
679 );
680 }
681
682 $ret['message'] = str_replace(
683 '%version',
684 $key,
685 _T("%version script has been successfully executed :)")
686 );
687 $ret['res'] = true;
688 $this->_report[] = $ret;
689 } catch (\RuntimeException $e) {
690 Analog::log(
691 $e->getMessage(),
692 Analog::ERROR
693 );
694 $ret['message'] = str_replace(
695 '%version',
696 $key,
697 _T("Unable to run %version update script :(")
698 );
699 $fatal_error = true;
700 $this->_report[] = $ret;
701 }
702 }
703
704 Analog::log(
705 str_replace('%s', $key, 'Upgrade to %s complete'),
706 Analog::INFO
707 );
708 }
709
710 return !$fatal_error;
711 }
712
713 /**
714 * Executes SQL queries
715 *
716 * @param Db $zdb Database instance
717 * @param string $sql_query SQL instructions
718 *
719 * @return boolean;
720 */
721 public function executeSql($zdb, $sql_query)
722 {
723 $queries_results = array();
724 $fatal_error = false;
725
726 // begin : copyright (2002) the phpbb group (support@phpbb.com)
727 // load in the sql parser
728 include_once GALETTE_ROOT . 'includes/sql_parse.php';
729
730 $sql_query = preg_replace('/galette_/', $this->_db_prefix, $sql_query);
731 $sql_query = remove_remarks($sql_query);
732
733 $sql_query = split_sql_file($sql_query, ';');
734
735 $zdb->connection->beginTransaction();
736
737 $sql_size = sizeof($sql_query);
738 for ($i = 0; $i < $sql_size; $i++) {
739 $query = trim($sql_query[$i]);
740 if ($query != '' && $query[0] != '-') {
741 //some output infos
742 $ret = array(
743 'message' => $query,
744 'res' => false
745 );
746
747 try {
748 $zdb->db->query(
749 $query,
750 Adapter::QUERY_MODE_EXECUTE
751 );
752 $ret['res'] = true;
753 } catch (Throwable $e) {
754 $log_lvl = Analog::WARNING;
755 //if error are on drop, DROP, rename or RENAME we can continue
756 $parts = explode(' ', $query, 1);
757 if (
758 (strcasecmp(trim($parts[0]), 'drop') != 0)
759 && (strcasecmp(trim($parts[0]), 'rename') != 0)
760 ) {
761 $log_lvl = Analog::ERROR;
762 $ret['debug'] = $e->getMessage();
763 $ret['query'] = $query;
764 $ret['res'] = false;
765 $fatal_error = true;
766 } else {
767 $ret['res'] = true;
768 }
769 Analog::log(
770 'Error executing query | ' . $e->getMessage(),
771 $log_lvl
772 );
773 }
774
775 $queries_results[] = $ret;
776 }
777 }
778
779 if ($fatal_error) {
780 try {
781 $zdb->connection->rollBack();
782 } catch (\PDOException $e) {
783 //to avoid php8/mysql autocommit issue
784 if ($zdb->isPostgres() || (!$zdb->isPostgres() && !str_contains($e->getMessage(), 'no active transaction'))) {
785 throw $e;
786 }
787 }
788 } else {
789 try {
790 $zdb->connection->commit();
791 } catch (\PDOException $e) {
792 //to avoid php8/mysql autocommit issue
793 if ($zdb->isPostgres() || (!$zdb->isPostgres() && !str_contains($e->getMessage(), 'no active transaction'))) {
794 throw $e;
795 }
796 }
797 }
798
799 $this->_report = array_merge($this->_report, $queries_results);
800 return !$fatal_error;
801 }
802
803 /**
804 * Retrieve database installation report
805 *
806 * @return array
807 */
808 public function getDbInstallReport()
809 {
810 return $this->_report;
811 }
812
813 /**
814 * Reinitialize report array
815 *
816 * @return void
817 */
818 public function reinitReport()
819 {
820 $this->_report = array();
821 }
822
823 /**
824 * Set step to super admin information
825 *
826 * @return void
827 */
828 public function atAdminStep()
829 {
830 $this->_step = self::STEP_ADMIN;
831 }
832
833 /**
834 * Are we at super admin information step?
835 *
836 * @return boolean
837 */
838 public function isAdminStep()
839 {
840 return $this->_step === self::STEP_ADMIN;
841 }
842
843 /**
844 * Set super administrator information
845 *
846 * @param string $login Login
847 * @param string $pass Password
848 *
849 * @return void
850 */
851 public function setAdminInfos($login, $pass)
852 {
853 $this->_admin_login = $login;
854 $this->_admin_pass = password_hash($pass, PASSWORD_BCRYPT);
855 }
856
857 /**
858 * Retrieve super admin login
859 *
860 * @return string
861 */
862 public function getAdminLogin()
863 {
864 return $this->_admin_login;
865 }
866
867 /**
868 * Retrieve super admin password
869 *
870 * @return string
871 */
872 public function getAdminPass()
873 {
874 return $this->_admin_pass;
875 }
876
877 /**
878 * Set step to Galette initialization
879 *
880 * @return void
881 */
882 public function atGaletteInitStep()
883 {
884 $this->_step = self::STEP_GALETTE_INIT;
885 }
886
887 /**
888 * Are we at Galette initialization step?
889 *
890 * @return boolean
891 */
892 public function isGaletteInitStep()
893 {
894 return $this->_step === self::STEP_GALETTE_INIT;
895 }
896
897 /**
898 * Load existing config
899 *
900 * @param array $post_data Data posted
901 * @param array $error_detected Errors array
902 *
903 * @return void
904 */
905 public function loadExistingConfig($post_data, &$error_detected)
906 {
907 if (file_exists(GALETTE_CONFIG_PATH . 'config.inc.php')) {
908 $existing = $this->loadExistingConfigFile($post_data);
909
910 if ($existing['db_type'] !== null) {
911 $this->setDbType($existing['db_type'], $error_detected);
912 }
913
914 if (
915 $existing['db_host'] !== null
916 || $existing['db_user'] !== null
917 || $existing['db_name'] !== null
918 ) {
919 $this->setDsn(
920 $existing['db_host'],
921 $existing['db_port'],
922 $existing['db_name'],
923 $existing['db_user'],
924 null
925 );
926 }
927
928 if ($existing['prefix'] !== null) {
929 $this->setTablesPrefix(
930 $existing['prefix']
931 );
932 }
933 }
934 }
935
936 /**
937 * Load contents from existing config file
938 *
939 * @param array $post_data Data posted
940 * @param boolean $pass Retrieve password
941 *
942 * @return array
943 */
944 private function loadExistingConfigFile($post_data = array(), $pass = false)
945 {
946 $existing = array(
947 'db_type' => null,
948 'db_host' => null,
949 'db_port' => null,
950 'db_user' => null,
951 'db_name' => null,
952 'prefix' => null
953 );
954
955 if (file_exists(GALETTE_CONFIG_PATH . 'config.inc.php')) {
956 $conf = file_get_contents(GALETTE_CONFIG_PATH . 'config.inc.php');
957 if ($conf !== false) {
958 if (!isset($post_data['install_dbtype'])) {
959 preg_match(
960 '/TYPE_DB["\'], ["\'](.*)["\']\);/',
961 $conf,
962 $matches
963 );
964 if (isset($matches[1])) {
965 $existing['db_type'] = $matches[1];
966 }
967 }
968 if (!isset($post_data['install_dbhost'])) {
969 preg_match(
970 '/HOST_DB["\'], ["\'](.*)["\']\);/',
971 $conf,
972 $matches
973 );
974 if (isset($matches[1])) {
975 $existing['db_host'] = $matches[1];
976 }
977 }
978 if (!isset($post_data['install_dbport'])) {
979 preg_match(
980 '/PORT_DB["\'], ["\'](.*)["\']\);/',
981 $conf,
982 $matches
983 );
984 if (isset($matches[1])) {
985 $existing['db_port'] = $matches[1];
986 }
987 }
988 if (!isset($post_data['install_dbuser'])) {
989 preg_match(
990 '/USER_DB["\'], ["\'](.*)["\']\);/',
991 $conf,
992 $matches
993 );
994 if (isset($matches[1])) {
995 $existing['db_user'] = $matches[1];
996 }
997 }
998 if (!isset($post_data['install_dbname'])) {
999 preg_match(
1000 '/NAME_DB["\'], ["\'](.*)["\']\);/',
1001 $conf,
1002 $matches
1003 );
1004 if (isset($matches[1])) {
1005 $existing['db_name'] = $matches[1];
1006 }
1007 }
1008
1009
1010 if (!isset($post_data['install_dbprefix'])) {
1011 preg_match(
1012 '/PREFIX_DB["\'], ["\'](.*)["\']\);/',
1013 $conf,
1014 $matches
1015 );
1016 if (isset($matches[1])) {
1017 $existing['prefix'] = $matches[1];
1018 }
1019 }
1020
1021 if ($pass === true) {
1022 preg_match(
1023 '/PWD_DB["\'], ["\'](.*)["\']\);/',
1024 $conf,
1025 $matches
1026 );
1027 if (isset($matches[1])) {
1028 $existing['pwd_db'] = $matches[1];
1029 }
1030 }
1031 }
1032 }
1033
1034 return $existing;
1035 }
1036
1037 /**
1038 * Write configuration file to disk
1039 *
1040 * @return boolean
1041 */
1042 public function writeConfFile()
1043 {
1044 $error = false;
1045 $ret = array(
1046 'message' => _T("Write configuration file"),
1047 'res' => false
1048 );
1049
1050 //if config file is already up-to-date, nothing to write
1051 $existing = $this->loadExistingConfigFile(array(), true);
1052
1053 if (
1054 isset($existing['db_type'])
1055 && $existing['db_type'] == $this->_db_type
1056 && isset($existing['db_host'])
1057 && $existing['db_host'] == $this->_db_host
1058 && isset($existing['db_port'])
1059 && $existing['db_port'] == $this->_db_port
1060 && isset($existing['db_user'])
1061 && $existing['db_user'] == $this->_db_user
1062 && isset($existing['pwd_db'])
1063 && $existing['pwd_db'] == $this->_db_pass
1064 && isset($existing['db_name'])
1065 && $existing['db_name'] == $this->_db_name
1066 && isset($existing['prefix'])
1067 && $existing['prefix'] == $this->_db_prefix
1068 ) {
1069 Analog::log(
1070 'Config file is already up-to-date, nothing to do.',
1071 Analog::INFO
1072 );
1073
1074 $this->_report[] = array(
1075 'message' => _T("Config file already exists and is up to date"),
1076 'res' => true
1077 );
1078 return true;
1079 }
1080
1081 $conffile = GALETTE_CONFIG_PATH . 'config.inc.php';
1082 if (
1083 is_writable(GALETTE_CONFIG_PATH)
1084 && (!file_exists($conffile) || file_exists($conffile) && is_writable($conffile))
1085 && $fd = @fopen($conffile, 'w')
1086 ) {
1087 $data = "<?php
1088 define('TYPE_DB', '" . $this->_db_type . "');
1089 define('HOST_DB', '" . $this->_db_host . "');
1090 define('PORT_DB', '" . $this->_db_port . "');
1091 define('USER_DB', '" . $this->_db_user . "');
1092 define('PWD_DB', '" . $this->_db_pass . "');
1093 define('NAME_DB', '" . $this->_db_name . "');
1094 define('PREFIX_DB', '" . $this->_db_prefix . "');
1095 ";
1096 fwrite($fd, $data);
1097 fclose($fd);
1098 $ret['res'] = true;
1099 Analog::log('Configuration file written on disk', Analog::INFO);
1100 } else {
1101 $str = str_replace(
1102 '%path',
1103 $conffile,
1104 _T("Unable to create configuration file (%path)")
1105 );
1106 Analog::log($str, Analog::WARNING);
1107 $ret['error'] = $str;
1108 $error = true;
1109 }
1110 $this->_report[] = $ret;
1111 return !$error;
1112 }
1113
1114 /**
1115 * Initialize Galette relevant objects
1116 *
1117 * @param I18n $i18n I18n
1118 * @param Db $zdb Database instance
1119 * @param Login $login Loged in instance
1120 *
1121 * @return boolean
1122 */
1123 public function initObjects(I18n $i18n, Db $zdb, Login $login)
1124 {
1125 if ($this->isInstall()) {
1126 $preferences = new Preferences($zdb, false);
1127 $ct = new \Galette\Entity\ContributionsTypes($zdb);
1128 $status = new \Galette\Entity\Status($zdb);
1129 include_once '../includes/fields_defs/members_fields.php';
1130 include_once '../includes/fields_defs/members_fields_cats.php';
1131 $fc = new \Galette\Entity\FieldsConfig(
1132 $zdb,
1133 \Galette\Entity\Adherent::TABLE,
1134 //@phpstan-ignore-next-line
1135 $members_fields,
1136 //@phpstan-ignore-next-line
1137 $members_fields_cats,
1138 true
1139 );
1140
1141 global $login;
1142 $login = new \Galette\Core\Login($zdb, $i18n);
1143 //$fc = new \Galette\Entity\FieldsCategories();
1144 $texts = new \Galette\Entity\Texts($preferences);
1145 $titles = new \Galette\Repository\Titles();
1146
1147 $models = new \Galette\Repository\PdfModels($zdb, $preferences, $login);
1148
1149 $this->_error = false;
1150
1151 //Install preferences
1152 $res = $preferences->installInit(
1153 $i18n->getID(),
1154 $this->getAdminLogin(),
1155 $this->getAdminPass()
1156 );
1157 $this->proceedReport(_T("Preferences"), $res);
1158
1159 //Install contributions types
1160 $res = $ct->installInit();
1161 $this->proceedReport(_T("Contributions types"), $res);
1162
1163 //Install statuses
1164 $res = $status->installInit();
1165 $this->proceedReport(_T("Status"), $res);
1166
1167 //Install fields configuration and categories
1168 $res = $fc->installInit();
1169 $this->proceedReport(_T("Fields config and categories"), $res);
1170
1171 //Install texts
1172 $res = $texts->installInit(false);
1173 $this->proceedReport(_T("Mails texts"), $res);
1174
1175 //Install titles
1176 $res = $titles->installInit($zdb);
1177 $this->proceedReport(_T("Titles"), $res);
1178
1179 //Install PDF models
1180 $res = $models->installInit(false);
1181 $this->proceedReport(_T("PDF Models"), $res);
1182
1183 return !$this->_error;
1184 } elseif ($this->isUpgrade()) {
1185 $preferences = new Preferences($zdb);
1186 $preferences->store();
1187 $this->proceedReport(_T("Update preferences"), true);
1188
1189 $models = new \Galette\Repository\PdfModels($zdb, $preferences, new Login($zdb, $i18n));
1190 $models->installInit(true);
1191 $this->proceedReport(_T("Update models"), true);
1192
1193 $texts = new \Galette\Entity\Texts($preferences);
1194 $texts->installInit(true);
1195 $this->proceedReport(_T("Mails texts"), true);
1196
1197 return true;
1198 }
1199 return false;
1200 }
1201
1202 /**
1203 * Proceed installation report for each Entity/Repository
1204 *
1205 * @param string $msg Report message title
1206 * @param mixed $res Initialialization result
1207 *
1208 * @return void
1209 */
1210 private function proceedReport($msg, $res)
1211 {
1212 $ret = array(
1213 'message' => $msg,
1214 'res' => false
1215 );
1216
1217 if ($res instanceof \Exception) {
1218 $ret['debug'] = $res->getMessage();
1219 $this->_error = true;
1220 } else {
1221 $ret['res'] = true;
1222 }
1223 $this->_report[] = $ret;
1224 }
1225 /**
1226 * Retrieve galette initialization report
1227 *
1228 * @return array
1229 */
1230 public function getInitializationReport()
1231 {
1232 return $this->_report;
1233 }
1234
1235 /**
1236 * Set step to database installation
1237 *
1238 * @return void
1239 */
1240 public function atEndStep()
1241 {
1242 $this->_step = self::STEP_END;
1243 }
1244
1245 /**
1246 * Are we at end step?
1247 *
1248 * @return boolean
1249 */
1250 public function isEndStep()
1251 {
1252 return $this->_step === self::STEP_END;
1253 }
1254
1255 /**
1256 * Set installed version if we're upgrading
1257 *
1258 * @param string $version Installed version
1259 *
1260 * @return void
1261 */
1262 public function setInstalledVersion($version)
1263 {
1264 $this->_installed_version = $version;
1265 }
1266
1267 /**
1268 * Current Galette installed version, according to database
1269 *
1270 * @param Db $zdb Database instance
1271 *
1272 * @return string|false
1273 */
1274 public function getCurrentVersion($zdb)
1275 {
1276 try {
1277 $db_ver = $zdb->getDbVersion(true);
1278 if (isset($this->versions_mapper[$db_ver])) {
1279 return $this->versions_mapper[$db_ver];
1280 } else {
1281 return (string)$db_ver;
1282 }
1283 } catch (\LogicException $e) {
1284 return false;
1285 }
1286 }
1287
1288 /**
1289 * Check if step is passed
1290 *
1291 * @param int $step Step
1292 *
1293 * @return boolean
1294 */
1295 public function isStepPassed($step)
1296 {
1297 return $this->_step > $step;
1298 }
1299 }