Passed
Push — main ( 324b47...7af4bb )
by Rafael
43:55
created

InstallController::doAlixar()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* Copyright (C) 2004-2007  Rodolphe Quiedeville    <[email protected]>
4
 * Copyright (C) 2004-2016  Laurent Destailleur     <[email protected]>
5
 * Copyright (C) 2004       Eric Seigne             <[email protected]>
6
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
7
 * Copyright (C) 2004       Sebastien DiCintio      <[email protected]>
8
 * Copyright (C) 2005       Marc Barilley / Ocebo   <[email protected]>
9
 * Copyright (C) 2005-2012  Regis Houssin           <[email protected]>
10
 * Copyright (C) 2013-2014  Juanjo Menent           <[email protected]>
11
 * Copyright (C) 2014       Marcos García           <[email protected]>
12
 * Copyright (C) 2015       Cedric GROSS            <[email protected]>
13
 * Copyright (C) 2015-2016  Raphaël Doursenaud      <[email protected]>
14
 * Copyright (C) 2024		MDW                     <[email protected]>
15
 * Copyright (C) 2024		Rafael San José         <[email protected]>
16
 *
17
 * This program is free software; you can redistribute it and/or modify
18
 * it under the terms of the GNU General Public License as published by
19
 * the Free Software Foundation; either version 3 of the License, or
20
 * (at your option) any later version.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU General Public License
28
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29
 */
30
31
namespace DoliModules\Install\Controller;
32
33
use DoliCore\Base\Config;
34
use DoliCore\Base\DolibarrViewController;
35
use DoliCore\Form\FormAdmin;
36
use DoliModules\Install\Lib\Check;
37
use DoliModules\Install\Lib\Status;
38
use DoliModules\User\Model\User;
39
use Illuminate\Database\Capsule\Manager as DB;
40
use modUser;
41
use PDO;
42
use stdClass;
43
44
require_once BASE_PATH . '/../Dolibarr/Lib/Admin.php';
45
require_once BASE_PATH . '/install/inc.php';
46
47
class InstallController extends DolibarrViewController
48
{
49
    /**
50
     * Set to true if we can continue with the installation
51
     *
52
     * @var bool
53
     */
54
    public bool $allow_install;
55
56
    /**
57
     * True if we want to force the use of https (recommended).
58
     *
59
     * @var bool
60
     */
61
    public bool $force_https;
62
63
    /**
64
     * It contains the html code that shows a select with the languages.
65
     *
66
     * @var string
67
     */
68
    public $selectLanguages;
69
70
    /**
71
     * It contains the html code that shows a select with the themes.
72
     *
73
     * @var string
74
     */
75
    public $selectThemes;
76
77
    /**
78
     * Contains the view subtitle
79
     *
80
     * @var string
81
     */
82
    public $subtitle;
83
84
    /**
85
     * Indicates whether to show the 'next' button.
86
     *
87
     * @var bool
88
     */
89
    public $nextButton;
90
91
    /**
92
     * Contains the JS code to be executed when the 'next' button is pressed
93
     *
94
     * @var string
95
     */
96
    public $nextButtonJs;
97
98
    /**
99
     * Multipurpose variable to send information to the view.
100
     *
101
     * @var stdClass
102
     */
103
    public $vars;
104
105
    /**
106
     * Code that is executed before the action is executed.
107
     *
108
     * @return bool
109
     */
110
    public function beforeAction(): bool
111
    {
112
        $this->vars = new stdClass();
113
114
        $https = $this->config->main->url ?? 'https';
115
        $this->force_https = (substr($https, 4, 1) === 's');
116
117
        return parent::beforeAction();
118
    }
119
120
    /**
121
     * Code that runs when "Refresh" button is pressed to set the
122
     * language and theme.
123
     *
124
     * @return bool
125
     */
126
    public function doRefresh(): bool
127
    {
128
        $this->config->main->language = getIfIsset('language', $this->config->main->language);
129
        $this->config->main->theme = getIfIsset('theme', $this->config->main->theme);
130
131
        Config::setMainConfig([
132
            'language' => $this->config->main->language,
133
            'theme' => $this->config->main->theme,
134
        ]);
135
        Config::saveConfig();
136
137
        return $this->doIndex();
138
    }
139
140
    /**
141
     * Perform a needs check for the application to determine if it meets all the
142
     * essential requirements.
143
     *
144
     * @return bool
145
     */
146
    public function doIndex(): bool
147
    {
148
        if (!isset($this->config->main->language)) {
149
            $this->config->main->language = 'auto';
150
        }
151
152
        Config::setMainConfig([
153
            'language' => getIfIsset('language', $this->config->main->language),
154
            'theme' => getIfIsset('theme', $this->config->main->theme ?? 'eldy'),
155
        ]);
156
157
        $form = new FormAdmin(null);
158
        $this->selectLanguages = $form->select_language($this->config->main->language, 'language', 1, 0, 0, 1);
159
        $this->selectThemes = $form->select_theme($this->config->main->theme);
160
161
        $this->langs->setDefaultLang($this->config->main->language);
162
        $this->langs->loadLangs(['main', 'admin', 'install']);
163
164
        $this->template = 'install/checked';
165
166
        $checks = Check::all();
167
168
        $value = $this->checkConfFile();
169
        if ($value['status'] !== Status::OK) {
170
            $checks[] = $value;
171
        }
172
173
        $conffile = Config::getDolibarrConfigFilename();
174
175
        if (!file_exists($conffile)) {
176
            $text = $this->langs->trans('YouMustCreateWithPermission', $conffile);
177
            $text .= '<br><br>';
178
            $text .= '<span class="opacitymedium">' . $this->langs->trans("CorrectProblemAndReloadPage", $_SERVER['PHP_SELF'] . '?testget=ok') . '</span>';
179
180
            $checks[] = [
181
                'status' => Status::FAIL,
182
                'text' => $text,
183
            ];
184
185
            return static::setIcons($checks);
186
        }
187
188
        $value = $this->checkIfWritable();
189
        if ($value['status'] !== Status::OK) {
190
            $checks[] = $value;
191
192
            return static::setIcons($checks);
193
        }
194
195
        /**
196
         * TODO: It is necessary to review what the next method does.
197
         */
198
        $value = $this->next();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $value is correct as $this->next() targeting DoliModules\Install\Cont...stallController::next() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
199
200
        return static::setIcons($checks);
201
    }
202
203
    /**
204
     * Ensures that the configuration file exists and can be read.
205
     *
206
     * @return array
207
     */
208
    private function checkConfFile(): array
209
    {
210
        $config_filename = Config::getDolibarrConfigFilename();
211
212
        clearstatcache();
213
        if (is_readable($config_filename) && filesize($config_filename) > 8) {
214
            $this->syslog("check: conf file '" . $config_filename . "' already defined");
215
            return ['status' => Status::OK];
216
        }
217
218
        // If not, we create it
219
        $this->syslog("check: we try to create conf file '" . $config_filename . "'");
220
221
        // First we try by copying example
222
        if (@copy($config_filename . ".example", $config_filename)) {
223
            // Success
224
            $this->syslog("check: successfully copied file " . $config_filename . ".example into " . $config_filename);
225
            return ['status' => Status::OK];
226
        }
227
228
        // If failed, we try to create an empty file
229
        $this->syslog("check: failed to copy file " . $config_filename . ".example into " . $config_filename . ". We try to create it.", LOG_WARNING);
230
231
        $fp = @fopen($config_filename, "w");
232
        if ($fp) {
233
            @fwrite($fp, '<?php');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fwrite(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

233
            /** @scrutinizer ignore-unhandled */ @fwrite($fp, '<?php');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
234
            @fwrite($fp, "\n");
235
            if (fclose($fp)) {
236
                return ['status' => Status::OK];
237
            }
238
        }
239
240
        $this->syslog("check: failed to create a new file " . $config_filename . " into current dir " . getcwd() . ". Please check permissions.", LOG_ERR);
241
        return [
242
            'status' => Status::FAIL,
243
            'text' => $this->langs->trans('ConfFileDoesNotExistsAndCouldNotBeCreated', 'conf.php')
244
        ];
245
    }
246
247
    /**
248
     * Returns an array with the checks carried out, indicating the
249
     * name of the action, if there is an error and the icon to display.
250
     *
251
     * @param array $checks
252
     * @return bool
253
     */
254
    private function setIcons(array $checks): bool
255
    {
256
        $ok = true;
257
        $this->vars->checks = [];
258
        foreach ($checks as $check) {
259
            if (!isset($check['text'])) {
260
                continue;
261
            }
262
            $value = [];
263
            $value['text'] = $check['text'];
264
            switch ($check['status']) {
265
                case Status::OK:
266
                    $value['ok'] = true;
267
                    $value['icon'] = 'tick';
268
                    break;
269
                case Status::WARNING:
270
                    $value['ok'] = true;
271
                    $value['icon'] = 'warning';
272
                    break;
273
                case Status::FAIL:
274
                    $value['ok'] = false;
275
                    $value['icon'] = 'error';
276
                    $ok = false;
277
            }
278
            $this->vars->checks[] = $value;
279
        }
280
281
        if (!$ok) {
282
            $this->vars->checks[] = [
283
                'ok' => false,
284
                'icon' => 'error',
285
                'text' => $this->langs->trans('ErrorGoBackAndCorrectParameters'),
286
            ];
287
        }
288
289
        return $ok;
290
    }
291
292
    /**
293
     * Checks if the configuration file can be edited.
294
     *
295
     * @return array
296
     */
297
    private function checkIfWritable()
298
    {
299
        $config_filename = Config::getDolibarrConfigFilename();
300
301
        if (is_dir($config_filename)) {
302
            return [
303
                'status' => Status::FAIL,
304
                'text' => $this->langs->trans('ConfFileMustBeAFileNotADir', $config_filename),
305
            ];
306
        }
307
308
        $this->allow_install = is_writable($config_filename);
309
        if (!$this->allow_install) {
310
            return [
311
                'status' => Status::FAIL,
312
                'text' => $this->langs->trans('ConfFileIsNotWritable', $config_filename),
313
            ];
314
        }
315
316
        return [
317
            'status' => Status::OK,
318
        ];
319
    }
320
321
    /**
322
     * Fill in the information about the options available to install and/or update.
323
     * TODO: This method needs major refactoring
324
     *
325
     * @return void
326
     * @throws \Exception
327
     */
328
    private function next()
329
    {
330
        $configFilename = Config::getDolibarrConfigFilename();
331
        $conf = Config::getConf();
332
        $config = Config::getConfig($conf);
333
334
        $ok = false;
335
        if (!empty($config->main_db_type) && !empty($config->main_document_root)) {
336
            $this->errorBadMainDocumentRoot = '';
337
            if ($config->main_document_root !== BASE_PATH) {
338
                $this->errorBadMainDocumentRoot = "A $configFilename file exists with a dolibarr_main_document_root to $config->main_document_root that seems wrong. Try to fix or remove the $configFilename file.";
339
                dol_syslog($this->errorBadMainDocumentRoot, LOG_WARNING);
340
            } else {
341
                // If password is encoded, we decode it
342
                // TODO: Pending
343
                if (preg_match('/crypted:/i', $config->main_db_pass) || !empty($dolibarr_main_db_encrypted_pass)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dolibarr_main_db_encrypted_pass seems to never exist and therefore empty should always be true.
Loading history...
344
                    require_once $this->dolibarr_main_document_root . '/core/lib/security.lib.php';
0 ignored issues
show
Bug introduced by
The property dolibarr_main_document_root does not exist on DoliModules\Install\Controller\InstallController. Did you mean dolibarr_main_db_encryption?
Loading history...
345
                    if (preg_match('/crypted:/i', $config->main_db_pass)) {
346
                        $dolibarr_main_db_encrypted_pass = preg_replace('/crypted:/i', '', $config->main_db_pass); // We need to set this as it is used to know the password was initially encrypted
347
                        $config->main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
348
                    } else {
349
                        $config->main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
350
                    }
351
                }
352
353
                // $conf already created in inc.php
354
                $this->conf->db->type = $config->main_db_type;
0 ignored issues
show
Bug introduced by
The property conf does not exist on DoliModules\Install\Controller\InstallController. Did you mean config?
Loading history...
355
                $this->conf->db->host = $config->main_db_host;
356
                $this->conf->db->port = $config->main_db_port;
357
                $this->conf->db->name = $config->main_db_name;
358
                $this->conf->db->user = $config->main_db_user;
359
                $this->conf->db->pass = $config->main_db_pass;
360
                $db = getDoliDBInstance($this->conf->db->type, $this->conf->db->host, $this->conf->db->user, $this->conf->db->pass, $this->conf->db->name, (int)$this->conf->db->port);
361
                if ($db->connected && $db->database_selected) {
362
                    $ok = true;
363
                }
364
            }
365
        }
366
367
        $this->vars->availableChoices = [];
368
        $this->vars->notAvailableChoices = [];
369
370
        // If database access is available, we set more variables
371
        // TODO: Pending
372
        if ($ok) {
373
            if (empty($dolibarr_main_db_encryption)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dolibarr_main_db_encryption seems to never exist and therefore empty should always be true.
Loading history...
374
                $dolibarr_main_db_encryption = 0;
375
            }
376
            $this->conf->db->dolibarr_main_db_encryption = $dolibarr_main_db_encryption;
377
            if (empty($dolibarr_main_db_cryptkey)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dolibarr_main_db_cryptkey seems to never exist and therefore empty should always be true.
Loading history...
378
                $dolibarr_main_db_cryptkey = '';
379
            }
380
            $this->conf->db->dolibarr_main_db_cryptkey = $dolibarr_main_db_cryptkey;
381
382
            $this->conf->setValues($db);
383
            // Reset forced setup after the setValues
384
            if (defined('SYSLOG_FILE')) {
385
                $this->conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
386
            }
387
            $this->conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
388
389
            // Current version is $this->conf->global->MAIN_VERSION_LAST_UPGRADE
390
            // Version to install is DOL_VERSION
391
            $dolibarrlastupgradeversionarray = preg_split('/[\.-]/', isset($this->conf->global->MAIN_VERSION_LAST_UPGRADE) ? $this->conf->global->MAIN_VERSION_LAST_UPGRADE : (isset($this->conf->global->MAIN_VERSION_LAST_INSTALL) ? $this->conf->global->MAIN_VERSION_LAST_INSTALL : ''));
392
            $dolibarrversiontoinstallarray = versiondolibarrarray();
393
        }
394
395
        $this->vars->printVersion = getDolGlobalString('MAIN_VERSION_LAST_UPGRADE') || getDolGlobalString('MAIN_VERSION_LAST_INSTALL');
396
397
        $foundrecommandedchoice = 0;
398
399
        if (empty($dolibarr_main_db_host)) {    // This means install process was not run
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dolibarr_main_db_host does not exist. Did you maybe mean $dolibarr_main_db_cryptkey?
Loading history...
400
            $foundrecommandedchoice = 1; // To show only once
401
        }
402
403
        /*
404
        $button = $this->allow_install
405
            ? '<input class="button" type="submit" name="action" value="' . $this->langs->trans("Start") . '">'
406
            : ($foundrecommandedchoice ? '<span class="warning">' : '') . $this->langs->trans("InstallNotAllowed") . ($foundrecommandedchoice ? '</span>' : '');
407
        */
408
409
        // TODO: We have to see how we can use the action, and that the text is displayed in the correct language
410
        $button = $this->allow_install
411
            ? '<input class="button" type="submit" name="action" value="start">' . $this->langs->trans("Start")
412
            : ($foundrecommandedchoice ? '<span class="warning">' : '') . $this->langs->trans("InstallNotAllowed") . ($foundrecommandedchoice ? '</span>' : '');
413
414
        // Show line of first install choice
415
        $choice = [
416
            'selected' => true,
417
            'short' => $this->langs->trans("FreshInstall"),
418
            'long' => $this->langs->trans("FreshInstallDesc"),
419
            'active' => $this->allow_install,
420
            'button' => $button,
421
        ];
422
423
        if (!isset($config->main_db_host) || empty($config->main_db_host)) {
424
            $choice['long'] .= '<br><div class="center"><div class="ok suggestedchoice">' . $this->langs->trans("InstallChoiceSuggested") . '</div></div>';
425
        }
426
427
        $this->vars->availableChoices[] = $choice;
428
429
        $positionkey = ($foundrecommandedchoice ? 999 : 0);
430
        if ($this->allow_install) {
431
            $available_choices[$positionkey] = $choice;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$available_choices was never initialized. Although not strictly required by PHP, it is generally a good practice to add $available_choices = array(); before regardless.
Loading history...
432
        } else {
433
            $notavailable_choices[$positionkey] = $choice;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$notavailable_choices was never initialized. Although not strictly required by PHP, it is generally a good practice to add $notavailable_choices = array(); before regardless.
Loading history...
434
        }
435
436
        // Show upgrade lines
437
        $allowupgrade = true;
438
        if (empty($config->main_db_host)) {    // This means install process was not run
439
            $allowupgrade = false;
440
        }
441
        if (getDolGlobalInt("MAIN_NOT_INSTALLED")) {
442
            $allowupgrade = false;
443
        }
444
        if (GETPOST('allowupgrade')) {
445
            $allowupgrade = true;
446
        }
447
448
        $this->vars->errorMigrations = false;
449
        $migrationscript = $this->getMigrationScript();
450
451
        $count = 0;
452
        foreach ($migrationscript as $migarray) {
453
            $choice = '';
454
455
            $count++;
456
            $recommended_choice = false;
457
            $version = DOL_VERSION;
458
            $versionfrom = $migarray['from'];
459
            $versionto = $migarray['to'];
460
            $versionarray = preg_split('/[\.-]/', $version);
461
            $dolibarrversionfromarray = preg_split('/[\.-]/', $versionfrom);
462
            $dolibarrversiontoarray = preg_split('/[\.-]/', $versionto);
463
            // Define string newversionxxx that are used for text to show
464
            $newversionfrom = preg_replace('/(\.[0-9]+)$/i', '.*', $versionfrom);
465
            $newversionto = preg_replace('/(\.[0-9]+)$/i', '.*', $versionto);
466
            $newversionfrombis = '';
467
            if (versioncompare($dolibarrversiontoarray, $versionarray) < -2) {  // From x.y.z -> x.y.z+1
468
                $newversionfrombis = ' ' . $this->langs->trans("or") . ' ' . $versionto;
469
            }
470
471
            if ($ok) {
472
                if (count($dolibarrlastupgradeversionarray) >= 2) { // If database access is available and last upgrade version is known
473
                    // Now we check if this is the first qualified choice
474
                    if (
475
                        $allowupgrade && empty($foundrecommandedchoice) &&
476
                        (versioncompare($dolibarrversiontoarray, $dolibarrlastupgradeversionarray) > 0 || versioncompare($dolibarrversiontoarray, $versionarray) < -2)
477
                    ) {
478
                        $foundrecommandedchoice = 1; // To show only once
479
                        $recommended_choice = true;
480
                    }
481
                } else {
482
                    // We cannot recommend a choice.
483
                    // A version of install may be known, but we need last upgrade.
484
                }
485
            }
486
487
            $button = $this->langs->trans("NotAvailable");
488
            if ($allowupgrade) {
489
                $disabled = false;
490
                if ($foundrecommandedchoice == 2) {
491
                    $disabled = true;
492
                }
493
                if ($foundrecommandedchoice == 1) {
494
                    $foundrecommandedchoice = 2;
495
                }
496
                if ($disabled) {
497
                    $button = '<span class="opacitymedium">' . $this->langs->trans("NotYetAvailable") . '</span>';
498
                } else {
499
                    // TODO: Pending fix how to pass the version in an action
500
                    $button = '<a class="button runupgrade" href="upgrade.php?action=upgrade' . ($count < count($migrationscript) ? '_' . $versionto : '') . '&selectlang=' . $this->vars->language . '&versionfrom=' . $versionfrom . '&versionto=' . $versionto . '">' . $this->langs->trans("Start") . '</a>';
501
                }
502
            }
503
504
            $choice = [
505
                'selected' => $recommended_choice,
506
                'short' => $this->langs->trans("Upgrade") . '<br>' . $newversionfrom . $newversionfrombis . ' -> ' . $newversionto,
507
                'long' => $this->langs->trans("UpgradeDesc"),
508
                'active' => $this->allow_install,
509
                'button' => $button,
510
            ];
511
512
            if ($recommended_choice) {
513
                $choice['long'] .= '<br><div class="center"><div class="ok suggestedchoice">' . $this->langs->trans("InstallChoiceSuggested") . '</div>';
514
                if ($count < count($migarray)) {
515
                    $choice['long'] .= $this->langs->trans('MigrateIsDoneStepByStep', DOL_VERSION);
516
                }
517
                $choice['long'] .= '</div>';
518
            }
519
520
            if ($allowupgrade) {
521
                $this->vars->availableChoices[$count] = $choice;
522
            } else {
523
                $this->vars->notAvailableChoices[$count] = $choice;
524
            }
525
        }
526
527
        // If there is no choice at all, we show all of them.
528
        if (empty($this->vars->availableChoices)) {
529
            $this->vars->availableChoices = $this->vars->notAvailableChoices;
530
            $this->vars->notAvailableChoices = [];
531
        }
532
533
        // Array of install choices
534
        krsort($this->vars->availableChoices, SORT_NATURAL);
535
    }
536
537
    /**
538
     * Gets an array with the SQL scripts for updating the database.
539
     * TODO: This method needs major refactoring
540
     *
541
     * @return array|mixed[]
542
     */
543
    private function getMigrationScript()
544
    {
545
        $dir = BASE_PATH . "/../Dolibarr/Modules/Install/mysql/migration/";   // We use mysql migration scripts whatever is database driver
546
        dolibarr_install_syslog("Scan sql files for migration files in " . $dir);
547
548
        // Get files list of migration file x.y.z-a.b.c.sql into /install/mysql/migration
549
        $migrationscript = [];
550
        $handle = opendir($dir);
551
        if (!is_resource($handle)) {
552
            $this->vars->errorMigrations = $this->langs->trans("ErrorCanNotReadDir", $dir);
553
            return [];
554
        }
555
556
        $versiontousetoqualifyscript = preg_replace('/-.*/', '', DOL_VERSION);
557
        while (($file = readdir($handle)) !== false) {
558
            $reg = [];
559
            if (preg_match('/^(\d+\.\d+\.\d+)-(\d+\.\d+\.\d+)\.sql$/i', $file, $reg)) {
560
                //var_dump(DOL_VERSION." ".$reg[2]." ".$versiontousetoqualifyscript." ".version_compare($versiontousetoqualifyscript, $reg[2]));
561
                if (!empty($reg[2]) && version_compare($versiontousetoqualifyscript, $reg[2]) >= 0) {
562
                    $migrationscript[] = ['from' => $reg[1], 'to' => $reg[2]];
563
                }
564
            }
565
        }
566
        return dol_sort_array($migrationscript, 'from', 'asc', 1);
567
    }
568
569
    public function doCreateAdminUser()
570
    {
571
        $this->langs->setDefaultLang($this->config->main->language);
572
        $this->langs->loadLangs(['main', 'admin', 'install']);
573
574
        $this->subtitle = $this->langs->trans("AdminAccountCreation");
575
        $this->template = 'install/create_admin_user';
576
577
        /*
578
        // Now we load forced value from install.forced.php file.
579
        $useforcedwizard = false;
580
        $forcedfile = "./install.forced.php";
581
        if ($conffile == "/etc/dolibarr/conf.php") {
582
            $forcedfile = "/etc/dolibarr/install.forced.php";
583
        }
584
        if (@file_exists($forcedfile)) {
585
            $useforcedwizard = true;
586
            include_once $forcedfile;
587
        }
588
        */
589
590
        dolibarr_install_syslog("--- step4: entering step4.php page");
591
592
        $this->vars->minLen = 8;
593
        $this->vars->login = (GETPOSTISSET("login")
594
            ? GETPOST("login", 'alpha')
595
            : (isset($force_install_dolibarrlogin)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $force_install_dolibarrlogin seems to never exist and therefore isset should always be false.
Loading history...
596
                ? $force_install_dolibarrlogin
597
                : ''
598
            ));
599
600
        $this->nextButton = true;
601
    }
602
603
    public function doVerifyAdminUser()
604
    {
605
        $this->langs->setDefaultLang($this->config->main->language);
606
        $this->langs->loadLangs(['main', 'admin', 'install']);
607
608
        $this->vars->login = GETPOST('login');
609
        $this->vars->pass = GETPOST('pass');
610
        $this->vars->pass_verif = GETPOST('pass_verif');
611
        $this->vars->minLen = 8;
612
613
        $this->nextButton = true;
614
615
        $this->vars->errors = [];
616
617
        if (empty($this->vars->login)) {
618
            $this->vars->errors[] = $this->langs->trans("PleaseTypeALogin");
619
        }
620
621
        if (strlen($this->vars->pass) < $this->vars->minLen) {
622
            $this->vars->errors[] = $this->langs->trans("PleaseTypePassword");
623
        }
624
625
        if ($this->vars->pass !== $this->vars->pass_verif) {
626
            $this->vars->errors[] = $this->langs->trans("PasswordsMismatch");
627
        }
628
629
        if (!empty($this->vars->errors)) {
630
            $this->template = 'install/create_admin_user';
631
            return false;
632
        }
633
634
        if (!$this->createUser($this->vars->login, $this->vars->pass)) {
635
            $this->template = 'install/create_admin_user';
636
            return false;
637
        }
638
639
        $this->template = 'install/finish';
640
        return true;
641
642
        $conffile = Config::getDolibarrConfigFilename();
0 ignored issues
show
Unused Code introduced by
$conffile = DoliCore\Bas...olibarrConfigFilename() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
643
644
645
        $error = 0;
646
        $ok = 0;
647
648
        $this->vars->config_read_only = !is_writable($conffile);
649
650
        $db = getDoliDBInstance(
651
            $this->config->db->type,
652
            $this->config->db->host,
653
            $this->config->db->user,
654
            $this->config->db->pass,
655
            $this->config->db->name,
656
            (int)$this->config->db->port
657
        );
658
659
        dolibarr_install_syslog("Exit " . $ret);
660
661
        dolibarr_install_syslog("--- step4: end");
662
663
        return true;
664
    }
665
666
    private function createUser(string $username, string $password): bool
667
    {
668
        $db = Config::getDb();
669
        $conf = Config::getConf();
670
671
        if (!isset($this->vars->errors)) {
672
            $this->vars->errors = [];
673
        }
674
675
        // Active module user
676
        include_once BASE_PATH . '/core/modules/modUser.class.php';
677
        $objMod = new modUser($db);
678
679
        dolibarr_install_syslog('step5: load module user ' . DOL_DOCUMENT_ROOT . "/core/modules/" . $file, LOG_INFO);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $file seems to be never defined.
Loading history...
680
        $result = $objMod->init();
681
        if (!$result) {
682
            $this->vars->errors[] = 'ERROR: failed to init module modUser';
683
            return false;
684
        }
685
686
        if (!$db->connected) {
687
            $this->vars->errors[] = $this->langs->trans("ErrorFailedToConnect");
688
            return false;
689
        }
690
691
        $conf->setValues($db);
692
        // Reset forced setup after the setValues
693
        if (defined('SYSLOG_FILE')) {
694
            $conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
695
        }
696
        $conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
697
698
        // Create admin user
699
        include_once BASE_PATH . '/user/class/user.class.php';
700
701
        // Set default encryption to yes, generate a salt and set default encryption algorithm (but only if there is no user yet into database)
702
        $sql = "SELECT u.rowid, u.pass, u.pass_crypted";
703
        $sql .= " FROM " . MAIN_DB_PREFIX . "user as u";
704
        $resql = $db->query($sql);
705
        if ($resql) {
706
            $numrows = $db->num_rows($resql);
707
            if ($numrows == 0) {
708
                // Define default setup for password encryption
709
                dolibarr_set_const($db, "DATABASE_PWD_ENCRYPTED", "1", 'chaine', 0, '', $conf->entity);
710
                dolibarr_set_const($db, "MAIN_SECURITY_SALT", dol_print_date(dol_now(), 'dayhourlog'), 'chaine', 0, '', 0); // All entities
711
                if (function_exists('password_hash')) {
712
                    dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'password_hash', 'chaine', 0, '', 0); // All entities
713
                } else {
714
                    dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'sha1md5', 'chaine', 0, '', 0); // All entities
715
                }
716
            }
717
718
            dolibarr_install_syslog('step5: DATABASE_PWD_ENCRYPTED = ' . getDolGlobalString('DATABASE_PWD_ENCRYPTED') . ' MAIN_SECURITY_HASH_ALGO = ' . getDolGlobalString('MAIN_SECURITY_HASH_ALGO'), LOG_INFO);
719
        }
720
721
        // Create user used to create the admin user
722
        $createuser = new User($db);
723
        $createuser->id = 0;
724
        $createuser->admin = 1;
725
726
        // Set admin user
727
        $newuser = new User($db);
728
        $newuser->lastname = 'SuperAdmin';
729
        $newuser->firstname = '';
730
        $newuser->login = $username;
731
        $newuser->pass = $password;
732
        $newuser->admin = 1;
733
        $newuser->entity = 0;
734
735
        $conf->global->USER_MAIL_REQUIRED = 0;            // Force global option to be sure to create a new user with no email
736
        $conf->global->USER_PASSWORD_GENERATED = '';    // To not use any rule for password validation
737
738
        $result = $newuser->create($createuser, 1);
739
        if ($result <= 0) {
740
            if ($result !== -6) {
741
                dolibarr_install_syslog('step5: FailedToCreateAdminLogin ' . $newuser->error, LOG_ERR);
742
                setEventMessages($this->langs->trans("FailedToCreateAdminLogin") . ' ' . $newuser->error, null, 'errors');
743
                //header("Location: step4.php?error=3&selectlang=$setuplang".(isset($login) ? '&login='.$login : ''));
744
                $this->vars->errors[] =
745
                    $this->langs->trans("FailedToCreateAdminLogin") . ': ' . $newuser->error .
746
                    '<br>' . $this->langs->trans("ErrorGoBackAndCorrectParameters");
747
                return false;
748
            }
749
            dolibarr_install_syslog('step5: AdminLoginAlreadyExists', LOG_WARNING);
750
            $this->vars->errors[] = $newuser->error;
751
        }
752
753
        $this->vars->errors[] = $this->langs->trans("AdminLoginCreatedSuccessfuly", $login);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $login seems to be never defined.
Loading history...
754
        $success = 1;
755
756
        // Insert MAIN_VERSION_FIRST_INSTALL in a dedicated transaction. So if it fails (when first install was already done), we can do other following requests.
757
        $db->begin();
758
        dolibarr_install_syslog('step5: set MAIN_VERSION_FIRST_INSTALL const to ' . $targetversion, LOG_DEBUG);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $targetversion seems to be never defined.
Loading history...
759
        $resql = $db->query("INSERT INTO " . MAIN_DB_PREFIX . "const(name, value, type, visible, note, entity) values(" . $db->encrypt('MAIN_VERSION_FIRST_INSTALL') . ", " . $db->encrypt($targetversion) . ", 'chaine', 0, 'Dolibarr version when first install', 0)");
760
        if ($resql) {
761
            $conf->global->MAIN_VERSION_FIRST_INSTALL = $targetversion;
762
            $db->commit();
763
        } else {
764
            //if (! $resql) dol_print_error($db,'Error in setup program');      // We ignore errors. Key may already exists
765
            $db->commit();
766
        }
767
768
        $db->begin();
769
770
        dolibarr_install_syslog('step5: set MAIN_VERSION_LAST_INSTALL const to ' . $targetversion, LOG_DEBUG);
771
        $resql = $db->query("DELETE FROM " . MAIN_DB_PREFIX . "const WHERE " . $db->decrypt('name') . " = 'MAIN_VERSION_LAST_INSTALL'");
772
        if (!$resql) {
773
            dol_print_error($db, 'Error in setup program');
774
        }
775
        $resql = $db->query("INSERT INTO " . MAIN_DB_PREFIX . "const(name,value,type,visible,note,entity) values(" . $db->encrypt('MAIN_VERSION_LAST_INSTALL') . ", " . $db->encrypt($targetversion) . ", 'chaine', 0, 'Dolibarr version when last install', 0)");
776
        if (!$resql) {
777
            dol_print_error($db, 'Error in setup program');
778
        }
779
        $conf->global->MAIN_VERSION_LAST_INSTALL = $targetversion;
780
781
        if ($useforcedwizard) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $useforcedwizard seems to be never defined.
Loading history...
782
            dolibarr_install_syslog('step5: set MAIN_REMOVE_INSTALL_WARNING const to 1', LOG_DEBUG);
783
            $resql = $db->query("DELETE FROM " . MAIN_DB_PREFIX . "const WHERE " . $db->decrypt('name') . " = 'MAIN_REMOVE_INSTALL_WARNING'");
784
            if (!$resql) {
785
                dol_print_error($db, 'Error in setup program');
786
            }
787
            // The install.lock file is created few lines later if version is last one or if option MAIN_ALWAYS_CREATE_LOCK_AFTER_LAST_UPGRADE is on
788
            /* No need to enable this
789
            $resql = $db->query("INSERT INTO ".MAIN_DB_PREFIX."const(name,value,type,visible,note,entity) values(".$db->encrypt('MAIN_REMOVE_INSTALL_WARNING').", ".$db->encrypt(1).", 'chaine', 1, 'Disable install warnings', 0)");
790
            if (!$resql) {
791
                dol_print_error($db, 'Error in setup program');
792
            }
793
            $conf->global->MAIN_REMOVE_INSTALL_WARNING = 1;
794
            */
795
        }
796
797
        // List of modules to enable
798
        $tmparray = array();
799
800
        // If we ask to force some modules to be enabled
801
        if (!empty($force_install_module)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $force_install_module seems to never exist and therefore empty should always be true.
Loading history...
802
            if (!defined('DOL_DOCUMENT_ROOT') && !empty($dolibarr_main_document_root)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dolibarr_main_document_root seems to never exist and therefore empty should always be true.
Loading history...
803
                define('DOL_DOCUMENT_ROOT', $dolibarr_main_document_root);
804
            }
805
806
            $tmparray = explode(',', $force_install_module);
807
        }
808
809
        $modNameLoaded = array();
810
811
        // Search modules dirs
812
        $modulesdir[] = $dolibarr_main_document_root . '/core/modules/';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dolibarr_main_document_root seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
$modulesdir was never initialized. Although not strictly required by PHP, it is generally a good practice to add $modulesdir = array(); before regardless.
Loading history...
813
814
        foreach ($modulesdir as $dir) {
815
            // Load modules attributes in arrays (name, numero, orders) from dir directory
816
            //print $dir."\n<br>";
817
            dol_syslog("Scan directory " . $dir . " for module descriptor files (modXXX.class.php)");
818
            $handle = @opendir($dir);
819
            if (is_resource($handle)) {
820
                while (($file = readdir($handle)) !== false) {
821
                    if (is_readable($dir . $file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') {
822
                        $modName = substr($file, 0, dol_strlen($file) - 10);
823
                        if ($modName) {
824
                            if (!empty($modNameLoaded[$modName])) {   // In cache of already loaded modules ?
825
                                $mesg = "Error: Module " . $modName . " was found twice: Into " . $modNameLoaded[$modName] . " and " . $dir . ". You probably have an old file on your disk.<br>";
826
                                setEventMessages($mesg, null, 'warnings');
827
                                dol_syslog($mesg, LOG_ERR);
828
                                continue;
829
                            }
830
831
                            try {
832
                                $res = include_once $dir . $file; // A class already exists in a different file will send a non catchable fatal error.
833
                                if (class_exists($modName)) {
834
                                    $objMod = new $modName($db);
835
                                    $modNameLoaded[$modName] = $dir;
836
                                    if (!empty($objMod->enabled_bydefault) && !in_array($file, $tmparray)) {
837
                                        $tmparray[] = $file;
838
                                    }
839
                                }
840
                            } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The type DoliModules\Install\Controller\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
841
                                dol_syslog("Failed to load " . $dir . $file . " " . $e->getMessage(), LOG_ERR);
842
                            }
843
                        }
844
                    }
845
                }
846
            }
847
        }
848
849
        // Loop on each modules to activate it
850
        if (!empty($tmparray)) {
851
            foreach ($tmparray as $modtoactivate) {
852
                $modtoactivatenew = preg_replace('/\.class\.php$/i', '', $modtoactivate);
853
                //print $this->langs->trans("ActivateModule", $modtoactivatenew).'<br>';
854
855
                $file = $modtoactivatenew . '.class.php';
856
                dolibarr_install_syslog('step5: activate module file=' . $file);
857
                $res = dol_include_once("/core/modules/" . $file);
858
859
                $res = activateModule($modtoactivatenew, 1);
860
                if (!empty($res['errors'])) {
861
                    print 'ERROR: failed to activateModule() file=' . $file;
862
                }
863
            }
864
            //print '<br>';
865
        }
866
867
        // Now delete the flag that say installation is not complete
868
        dolibarr_install_syslog('step5: remove MAIN_NOT_INSTALLED const');
869
        $resql = $db->query("DELETE FROM " . MAIN_DB_PREFIX . "const WHERE " . $db->decrypt('name') . " = 'MAIN_NOT_INSTALLED'");
870
        if (!$resql) {
871
            dol_print_error($db, 'Error in setup program');
872
        }
873
874
        // May fail if parameter already defined
875
        dolibarr_install_syslog('step5: set the default language');
876
        $resql = $db->query("INSERT INTO " . MAIN_DB_PREFIX . "const(name,value,type,visible,note,entity) VALUES (" . $db->encrypt('MAIN_LANG_DEFAULT') . ", " . $db->encrypt($setuplang) . ", 'chaine', 0, 'Default language', 1)");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $setuplang seems to be never defined.
Loading history...
877
        //if (! $resql) dol_print_error($db,'Error in setup program');
878
879
        $db->commit();
880
        return true;
881
    }
882
883
    public function checkDatabase()
884
    {
885
        if (isset($_POST['return'])) {
886
            return $this->doConfig();
887
        }
888
889
        $ok = 0;
890
891
        $this->template = 'install/db_update';
892
        $this->subtitle = $this->langs->trans("CreateDatabaseObjects");
893
        $this->nextButton = true;
894
895
// This page can be long. We increase the time allowed. / Cette page peut etre longue. On augmente le delai autorise.
896
// Only works if you are not in safe_mode. / Ne fonctionne que si on est pas en safe_mode.
897
898
        $err = error_reporting();
899
        error_reporting(0);      // Disable all errors
900
//error_reporting(E_ALL);
901
        @set_time_limit(1800);   // Need 1800 on some very slow OS like Windows 7/64
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

901
        /** @scrutinizer ignore-unhandled */ @set_time_limit(1800);   // Need 1800 on some very slow OS like Windows 7/64

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
902
        error_reporting($err);
903
904
        $action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : (empty($argv[1]) ? '' : $argv[1]);
905
        $setuplang = $this->config->main->language;
906
907
        $conffile = Config::getDolibarrConfigFilename();
908
        //$conf = Config::getConfig();
909
        //$this->conf = Config::getConf();
910
911
        /**
912
         * El valor de "$this->config->db->type" puede ser 'mysqli' o 'pgsql'
913
         * 1: 'mysqli'
914
         * 2: 'pgsql'
915
         * 3: No usado
916
         * 4: No usado
917
         * 5: No usado
918
         */
919
920
        // Now we load forced values from install.forced.php file.
921
        /*
922
        $useforcedwizard = false;
923
        $forcedfile = "./install.forced.php";
924
        if ($conffile == "/etc/dolibarr/conf.php") {
925
            $forcedfile = "/etc/dolibarr/install.forced.php";
926
        }
927
        if (@file_exists($forcedfile)) {
928
            $useforcedwizard = true;
929
            include_once $forcedfile;
930
            // test for travis
931
            if (!empty($argv[1]) && $argv[1] == "set") {
932
                $action = "set";
933
            }
934
        }
935
        */
936
937
        dolibarr_install_syslog("--- step2: entering step2.php page");
938
939
        $this->vars->config_read_only = !is_writable($conffile);
940
941
        // Test if we can run a first install process
942
        if (!is_writable($conffile)) {
943
            $this->vars->config_filename = $conffile;
944
            return false;
945
        }
946
947
        $error = 0;
948
        $db = Config::getDb();
949
950
        $checks = [];
951
952
        if ($db->connected) {
953
            $text = $this->langs->trans('ServerConnection') . ': <strong>' . $this->config->db->host . '</strong>';
954
            $status = Status::OK;
955
        } else {
956
            $text = 'Failed to connect to server: ' . $this->config->db->host;
957
            $status = Status::FAIL;
958
        }
959
        $checks[] = [
960
            'status' => $status,
961
            'text' => $text,
962
        ];
963
964
        $ok = ($status === Status::OK);
965
966
        if ($ok) {
967
            if ($db->database_selected) {
968
                dolibarr_install_syslog("step2: successful connection to database: " . $this->config->db->name);
969
            } else {
970
                dolibarr_install_syslog("step2: failed connection to database :" . $this->config->db->name, LOG_ERR);
971
                $checks[] = [
972
                    'status' => Status::FAIL,
973
                    'text' => 'Failed to select database ' . $this->config->db->name,
974
                ];
975
            }
976
977
            // Display version / Affiche version
978
            $version = $db->getVersion();
979
            $versionarray = $db->getVersionArray();
980
981
            $checks[] = [
982
                'text' => $this->langs->trans('DatabaseVersion') . ': <strong>' . $version . '</strong>',
983
            ];
984
            //print '<td class="right">'.join('.',$versionarray).'</td></tr>';
985
986
            $checks[] = [
987
                'text' => $this->langs->trans('DatabaseName') . ': <strong>' . $db->database_name . '</strong>',
988
            ];
989
            //print '<td class="right">'.join('.',$versionarray).'</td></tr>';
990
        }
991
992
        $requestnb = 0;
993
994
        // To disable some code, so you can call step2 with url like
995
        // http://localhost/dolibarrnew/install/step2.php?action=set&token='.newToken().'&createtables=0&createkeys=0&createfunctions=0&createdata=llx_20_c_departements
996
        $createtables = GETPOSTISSET('createtables') ? GETPOST('createtables') : 1;
997
        $createkeys = GETPOSTISSET('createkeys') ? GETPOST('createkeys') : 1;
998
        $createfunctions = GETPOSTISSET('createfunctions') ? GETPOST('createfunction') : 1;
999
        $createdata = GETPOSTISSET('createdata') ? GETPOST('createdata') : 1;
1000
1001
1002
        // To say that SQL we pass to query are already escaped for mysql, so we need to unescape them
1003
        if (property_exists($db, 'unescapeslashquot')) {
1004
            $db->unescapeslashquot = true;
1005
        }
1006
1007
        /**************************************************************************************
1008
         *
1009
         * Load files tables/*.sql (not the *.key.sql). Files with '-xxx' in name are excluded (they will be loaded during activation of module 'xxx').
1010
         * To do before the files *.key.sql
1011
         *
1012
         ***************************************************************************************/
1013
        if ($ok && $createtables) {
1014
            // We always choose in mysql directory (Conversion is done by driver to translate SQL syntax)
1015
            $dir = realpath(BASE_PATH . '/../Dolibarr/Modules/Install/mysql/tables/') . DIRECTORY_SEPARATOR;
1016
1017
            $ok = 0;
1018
            $handle = opendir($dir);
1019
            dolibarr_install_syslog("step2: open tables directory " . $dir . " handle=" . $handle);
1020
            $tablefound = 0;
1021
            $tabledata = [];
1022
            if (is_resource($handle)) {
1023
                while (($file = readdir($handle)) !== false) {
1024
                    if (preg_match('/\.sql$/i', $file) && preg_match('/^llx_/i', $file) && !preg_match('/\.key\.sql$/i', $file) && !preg_match('/\-/', $file)) {
1025
                        $tablefound++;
1026
                        $tabledata[] = $file;
1027
                    }
1028
                }
1029
                closedir($handle);
1030
            }
1031
1032
            // Sort list of sql files on alphabetical order (load order is important)
1033
            sort($tabledata);
1034
            foreach ($tabledata as $file) {
1035
                $name = substr($file, 0, dol_strlen($file) - 4);
1036
                $buffer = '';
1037
                $fp = fopen($dir . $file, "r");
1038
                if ($fp) {
1039
                    while (!feof($fp)) {
1040
                        $buf = fgets($fp, 4096);
1041
                        if (substr($buf, 0, 2) != '--') {
1042
                            $buf = preg_replace('/--(.+)*/', '', $buf);
1043
                            $buffer .= $buf;
1044
                        }
1045
                    }
1046
                    fclose($fp);
1047
1048
                    $buffer = trim($buffer);
1049
                    if ($this->config->db->type == 'mysql' || $this->config->db->type == 'mysqli') {    // For Mysql 5.5+, we must replace type=innodb with ENGINE=innodb
1050
                        $buffer = preg_replace('/type=innodb/i', 'ENGINE=innodb', $buffer);
1051
                    } else {
1052
                        // Keyword ENGINE is MySQL-specific, so scrub it for
1053
                        // other database types (mssql, pgsql)
1054
                        $buffer = preg_replace('/type=innodb/i', '', $buffer);
1055
                        $buffer = preg_replace('/ENGINE=innodb/i', '', $buffer);
1056
                    }
1057
1058
                    // Replace the prefix tables
1059
                    if ($this->config->db->prefix != 'llx_') {
1060
                        $buffer = preg_replace('/llx_/i', $this->config->db->prefix, $buffer);
1061
                    }
1062
1063
                    //print "<tr><td>Creation of table $name/td>";
1064
                    $requestnb++;
1065
1066
                    dolibarr_install_syslog("step2: request: " . $buffer);
1067
                    $resql = $db->query($buffer, 0, 'dml');
1068
                    if ($resql) {
1069
                        // print "<td>OK request ==== $buffer</td></tr>";
1070
                        $db->free($resql);
1071
                    } else {
1072
                        if (
1073
                            $db->errno() == 'DB_ERROR_TABLE_ALREADY_EXISTS' ||
1074
                            $db->errno() == 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS'
1075
                        ) {
1076
                            //print "<td>already existing</td></tr>";
1077
                        } else {
1078
                            $text = $this->langs->trans("CreateTableAndPrimaryKey", $name)
1079
                                . "\n" . $this->langs->trans("Request") . ' ' . $requestnb . ' : ' . $buffer
1080
                                . "\n" . 'Executed query: ' . $db->lastquery
1081
                                . "\n" . '<span class="error">' . $this->langs->trans("ErrorSQL") . " " . $db->errno() . " " . $db->error() . '</span>';
1082
                            $checks[] = [
1083
                                'text' => $text,
1084
                                'status' => Status::FAIL,
1085
                            ];
1086
                            $error++;
1087
                        }
1088
                    }
1089
                } else {
1090
                    $text = $this->langs->trans("CreateTableAndPrimaryKey", $name)
1091
                        . "\n" . $this->langs->trans("CreateTableAndPrimaryKey", $name)
1092
                        . "\n" . '<span class="error">' . $this->langs->trans("Error") . ' Failed to open file ' . $dir . $file . '</span>';
1093
                    $checks[] = [
1094
                        'text' => $text,
1095
                        'status' => Status::FAIL,
1096
                    ];
1097
                    $error++;
1098
                    dolibarr_install_syslog("step2: failed to open file " . $dir . $file, LOG_ERR);
1099
                }
1100
            }
1101
1102
            if ($tablefound) {
1103
                if ($error == 0) {
1104
                    $checks[] = [
1105
                        'text' => $this->langs->trans("TablesAndPrimaryKeysCreation"),
1106
                        'status' => Status::OK,
1107
                    ];
1108
                    $ok = 1;
1109
                }
1110
            } else {
1111
                //print '<tr><td>' . $this->langs->trans("ErrorFailedToFindSomeFiles", $dir) . '</td><td><img src="../theme/eldy/img/error.png" alt="Error"></td></tr>';
1112
                $checks[] = [
1113
                    'text' => $this->langs->trans("FileIntegritySomeFilesWereRemovedOrModified", $dir),
1114
                    'status' => Status::FAIL,
1115
                ];
1116
                dolibarr_install_syslog("step2: failed to find files to create database in directory " . $dir, LOG_ERR);
1117
            }
1118
        }
1119
1120
1121
        /***************************************************************************************
1122
         *
1123
         * Load files tables/*.key.sql. Files with '-xxx' in name are excluded (they will be loaded during activation of module 'xxx').
1124
         * To do after the files *.sql
1125
         *
1126
         ***************************************************************************************/
1127
        if ($ok && $createkeys) {
1128
            // We always choose in mysql directory (Conversion is done by driver to translate SQL syntax)
1129
            $dir = realpath(BASE_PATH . '/../Dolibarr/Modules/Install/mysql/tables/') . DIRECTORY_SEPARATOR;
1130
1131
            $okkeys = 0;
1132
            $handle = opendir($dir);
1133
            dolibarr_install_syslog("step2: open keys directory " . $dir . " handle=" . $handle);
1134
            $tablefound = 0;
1135
            $tabledata = [];
1136
            if (is_resource($handle)) {
1137
                while (($file = readdir($handle)) !== false) {
1138
                    if (preg_match('/\.sql$/i', $file) && preg_match('/^llx_/i', $file) && preg_match('/\.key\.sql$/i', $file) && !preg_match('/\-/', $file)) {
1139
                        $tablefound++;
1140
                        $tabledata[] = $file;
1141
                    }
1142
                }
1143
                closedir($handle);
1144
            }
1145
1146
            // Sort list of sql files on alphabetical order (load order is important)
1147
            sort($tabledata);
1148
            foreach ($tabledata as $file) {
1149
                $name = substr($file, 0, dol_strlen($file) - 4);
1150
                //print "<tr><td>Creation of table $name</td>";
1151
                $buffer = '';
1152
                $fp = fopen($dir . $file, "r");
1153
                if ($fp) {
1154
                    while (!feof($fp)) {
1155
                        $buf = fgets($fp, 4096);
1156
1157
                        // Special case of lines allowed for some version only
1158
                        // MySQL
1159
                        if ($choix == 1 && preg_match('/^--\sV([0-9\.]+)/i', $buf, $reg)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $choix seems to be never defined.
Loading history...
1160
                            $versioncommande = explode('.', $reg[1]);
1161
                            //var_dump($versioncommande);
1162
                            //var_dump($versionarray);
1163
                            if (
1164
                                count($versioncommande) && count($versionarray)
1165
                                && versioncompare($versioncommande, $versionarray) <= 0
1166
                            ) {
1167
                                // Version qualified, delete SQL comments
1168
                                $buf = preg_replace('/^--\sV([0-9\.]+)/i', '', $buf);
1169
                                //print "Ligne $i qualifiee par version: ".$buf.'<br>';
1170
                            }
1171
                        }
1172
                        // PGSQL
1173
                        if ($choix == 2 && preg_match('/^--\sPOSTGRESQL\sV([0-9\.]+)/i', $buf, $reg)) {
1174
                            $versioncommande = explode('.', $reg[1]);
1175
                            //var_dump($versioncommande);
1176
                            //var_dump($versionarray);
1177
                            if (
1178
                                count($versioncommande) && count($versionarray)
1179
                                && versioncompare($versioncommande, $versionarray) <= 0
1180
                            ) {
1181
                                // Version qualified, delete SQL comments
1182
                                $buf = preg_replace('/^--\sPOSTGRESQL\sV([0-9\.]+)/i', '', $buf);
1183
                                //print "Ligne $i qualifiee par version: ".$buf.'<br>';
1184
                            }
1185
                        }
1186
1187
                        // Add line if no comment
1188
                        if (!preg_match('/^--/i', $buf)) {
1189
                            $buffer .= $buf;
1190
                        }
1191
                    }
1192
                    fclose($fp);
1193
1194
                    // If several requests, we loop on each
1195
                    $listesql = explode(';', $buffer);
1196
                    foreach ($listesql as $req) {
1197
                        $buffer = trim($req);
1198
                        if ($buffer) {
1199
                            // Replace the prefix tables
1200
                            if ($this->config->db->prefix != 'llx_') {
1201
                                $buffer = preg_replace('/llx_/i', $this->config->db->prefix, $buffer);
1202
                            }
1203
1204
                            //print "<tr><td>Creation of keys and table index $name: '$buffer'</td>";
1205
                            $requestnb++;
1206
1207
                            dolibarr_install_syslog("step2: request: " . $buffer);
1208
                            $resql = $db->query($buffer, 0, 'dml');
1209
                            if ($resql) {
1210
                                //print "<td>OK request ==== $buffer</td></tr>";
1211
                                $db->free($resql);
1212
                            } else {
1213
                                if (
1214
                                    $db->errno() == 'DB_ERROR_KEY_NAME_ALREADY_EXISTS' ||
1215
                                    $db->errno() == 'DB_ERROR_CANNOT_CREATE' ||
1216
                                    $db->errno() == 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS' ||
1217
                                    $db->errno() == 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS' ||
1218
                                    preg_match('/duplicate key name/i', $db->error())
1219
                                ) {
1220
                                    //print "<td>Deja existante</td></tr>";
1221
                                    $key_exists = 1;
1222
                                } else {
1223
                                    $text = $this->langs->trans("CreateOtherKeysForTable", $name)
1224
                                        . "\n" . $this->langs->trans("Request") . ' ' . $requestnb . ' : ' . $db->lastqueryerror()
1225
                                        . "\n" . '<span class="error">' . $this->langs->trans("ErrorSQL") . " " . $db->errno() . " " . $db->error() . '</span>';
1226
                                    $checks[] = [
1227
                                        'text' => $text,
1228
                                        'status' => Status::FAIL,
1229
                                    ];
1230
                                    $error++;
1231
                                }
1232
                            }
1233
                        }
1234
                    }
1235
                } else {
1236
                    $text = $this->langs->trans("CreateOtherKeysForTable", $name)
1237
                        . "\n" . '<span class="error">' . $this->langs->trans("Error") . ' Failed to open file ' . $dir . $file . '</span>';
1238
                    $checks[] = [
1239
                        'text' => $text,
1240
                        'status' => Status::FAIL,
1241
                    ];
1242
                    $error++;
1243
                    dolibarr_install_syslog("step2: failed to open file " . $dir . $file, LOG_ERR);
1244
                }
1245
            }
1246
1247
            if ($tablefound && $error == 0) {
1248
                $checks[] = [
1249
                    'text' => $this->langs->trans("OtherKeysCreation"),
1250
                    'status' => Status::OK,
1251
                ];
1252
                $okkeys = 1;
1253
            }
1254
        }
1255
1256
1257
        /***************************************************************************************
1258
         *
1259
         * Load the file 'functions.sql'
1260
         *
1261
         ***************************************************************************************/
1262
        if ($ok && $createfunctions) {
1263
            // For this file, we use a directory according to database type
1264
            switch ($this->config->db->db_type) {
1265
                case 'mysqli':
1266
                    $dir = "mysql/functions/";
1267
                    break;
1268
                case 'pgsql':
1269
                    $dir = "pgsql/functions/";
1270
                    break;
1271
                case 'mssql':
1272
                    $dir = "mssql/functions/";
1273
                    break;
1274
                case 'sqlite3':
1275
                    $dir = "sqlite3/functions/";
1276
                    break;
1277
            }
1278
            $dir = realpath(BASE_PATH . '/../Dolibarr/Modules/Install/' . $dir) . DIRECTORY_SEPARATOR;
1279
1280
            // Creation of data
1281
            $file = "functions.sql";
1282
            if (file_exists($dir . $file)) {
1283
                $fp = fopen($dir . $file, "r");
1284
                dolibarr_install_syslog("step2: open function file " . $dir . $file . " handle=" . $fp);
1285
                if ($fp) {
1286
                    $buffer = '';
1287
                    while (!feof($fp)) {
1288
                        $buf = fgets($fp, 4096);
1289
                        if (substr($buf, 0, 2) != '--') {
1290
                            $buffer .= $buf . "§";
1291
                        }
1292
                    }
1293
                    fclose($fp);
1294
                }
1295
                //$buffer=preg_replace('/;\';/',";'§",$buffer);
1296
1297
                // If several requests, we loop on each of them
1298
                $listesql = explode('§', $buffer);
1299
                foreach ($listesql as $buffer) {
1300
                    $buffer = trim($buffer);
1301
                    if ($buffer) {
1302
                        // Replace the prefix in table names
1303
                        if ($this->config->db->prefix != 'llx_') {
1304
                            $buffer = preg_replace('/llx_/i', $this->config->db->prefix, $buffer);
1305
                        }
1306
                        dolibarr_install_syslog("step2: request: " . $buffer);
1307
                        print "<!-- Insert line : " . $buffer . "<br>-->\n";
1308
                        $resql = $db->query($buffer, 0, 'dml');
1309
                        if ($resql) {
1310
                            $ok = 1;
1311
                            $db->free($resql);
1312
                        } else {
1313
                            if (
1314
                                $db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS'
1315
                                || $db->errno() == 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'
1316
                            ) {
1317
                                //print "Insert line : ".$buffer."<br>\n";
1318
                            } else {
1319
                                $ok = 0;
1320
1321
                                $text = $this->langs->trans("FunctionsCreation")
1322
                                    . "\n" . $this->langs->trans("Request") . ' ' . $requestnb . ' : ' . $buffer
1323
                                    . "\n" . '<span class="error">' . $this->langs->trans("ErrorSQL") . " " . $db->errno() . " " . $db->error() . '</span>';
1324
                                $checks[] = [
1325
                                    'text' => $text,
1326
                                    'status' => Status::FAIL,
1327
                                ];
1328
                                $error++;
1329
                            }
1330
                        }
1331
                    }
1332
                }
1333
1334
                $checks[] = [
1335
                    'text' => $this->langs->trans("FunctionsCreation"),
1336
                    'status' => $ok ? Status::OK : Status::FAIL,
1337
                ];
1338
            }
1339
        }
1340
1341
1342
        /***************************************************************************************
1343
         *
1344
         * Load files data/*.sql. Files with '-xxx' in name are excluded (they will be loaded during activation of module 'xxx').
1345
         *
1346
         ***************************************************************************************/
1347
        if ($ok && $createdata) {
1348
            // We always choose in mysql directory (Conversion is done by driver to translate SQL syntax)
1349
            $dir = "mysql/data/";
1350
1351
            // Insert data
1352
            $handle = opendir($dir);
1353
            dolibarr_install_syslog("step2: open directory data " . $dir . " handle=" . $handle);
1354
            $tablefound = 0;
1355
            $tabledata = [];
1356
            if (is_resource($handle)) {
1357
                while (($file = readdir($handle)) !== false) {
1358
                    if (preg_match('/\.sql$/i', $file) && preg_match('/^llx_/i', $file) && !preg_match('/\-/', $file)) {
1359
                        if (preg_match('/^llx_accounting_account_/', $file)) {
1360
                            continue; // We discard data file of chart of account. This will be loaded when a chart is selected.
1361
                        }
1362
1363
                        //print 'x'.$file.'-'.$createdata.'<br>';
1364
                        if (is_numeric($createdata) || preg_match('/' . preg_quote($createdata) . '/i', $file)) {
1365
                            $tablefound++;
1366
                            $tabledata[] = $file;
1367
                        }
1368
                    }
1369
                }
1370
                closedir($handle);
1371
            }
1372
1373
            // Sort list of data files on alphabetical order (load order is important)
1374
            sort($tabledata);
1375
            foreach ($tabledata as $file) {
1376
                $name = substr($file, 0, dol_strlen($file) - 4);
1377
                $fp = fopen($dir . $file, "r");
1378
                dolibarr_install_syslog("step2: open data file " . $dir . $file . " handle=" . $fp);
1379
                if ($fp) {
1380
                    $arrayofrequests = [];
1381
                    $linefound = 0;
1382
                    $linegroup = 0;
1383
                    $sizeofgroup = 1; // Grouping request to have 1 query for several requests does not works with mysql, so we use 1.
1384
1385
                    // Load all requests
1386
                    while (!feof($fp)) {
1387
                        $buffer = fgets($fp, 4096);
1388
                        $buffer = trim($buffer);
1389
                        if ($buffer) {
1390
                            if (substr($buffer, 0, 2) == '--') {
1391
                                continue;
1392
                            }
1393
1394
                            if ($linefound && ($linefound % $sizeofgroup) == 0) {
1395
                                $linegroup++;
1396
                            }
1397
                            if (empty($arrayofrequests[$linegroup])) {
1398
                                $arrayofrequests[$linegroup] = $buffer;
1399
                            } else {
1400
                                $arrayofrequests[$linegroup] .= " " . $buffer;
1401
                            }
1402
1403
                            $linefound++;
1404
                        }
1405
                    }
1406
                    fclose($fp);
1407
1408
                    dolibarr_install_syslog("step2: found " . $linefound . " records, defined " . count($arrayofrequests) . " group(s).");
1409
1410
                    $okallfile = 1;
1411
                    $db->begin();
1412
1413
                    // We loop on each requests of file
1414
                    foreach ($arrayofrequests as $buffer) {
1415
                        // Replace the tables prefixes
1416
                        if ($this->config->db->prefix != 'llx_') {
1417
                            $buffer = preg_replace('/llx_/i', $this->config->db->prefix, $buffer);
1418
                        }
1419
1420
                        //dolibarr_install_syslog("step2: request: " . $buffer);
1421
                        $resql = $db->query($buffer, 1);
1422
                        if ($resql) {
1423
                            //$db->free($resql);     // Not required as request we launch here does not return memory needs.
1424
                        } else {
1425
                            if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
1426
                                //print "<tr><td>Insertion ligne : $buffer</td><td>";
1427
                            } else {
1428
                                $ok = 0;
1429
                                $okallfile = 0;
1430
                                print '<span class="error">' . $this->langs->trans("ErrorSQL") . " : " . $db->lasterrno() . " - " . $db->lastqueryerror() . " - " . $db->lasterror() . "</span><br>";
1431
                            }
1432
                        }
1433
                    }
1434
1435
                    if ($okallfile) {
1436
                        $db->commit();
1437
                    } else {
1438
                        $db->rollback();
1439
                    }
1440
                }
1441
            }
1442
1443
            $checks[] = [
1444
                'text' => $this->langs->trans("ReferenceDataLoading"),
1445
                'status' => $ok ? Status::OK : Status::FAIL,
1446
            ];
1447
        }
1448
1449
        $ret = 0;
1450
        if (!$ok && isset($argv[1])) {
1451
            $ret = 1;
1452
        }
1453
        dolibarr_install_syslog("Exit " . $ret);
1454
1455
        dolibarr_install_syslog("- step2: end");
1456
1457
// Force here a value we need after because master.inc.php is not loaded into step2.
1458
// This code must be similar with the one into main.inc.php
1459
1460
        $this->vars->hash_unique_id = dol_hash('dolibarr' . $this->config->main->unique_id, 'sha256');   // Note: if the global salt changes, this hash changes too so ping may be counted twice. We don't mind. It is for statistics purpose only.
1461
1462
        return static::setIcons($checks);
1463
    }
1464
1465
    public function doConfig(): bool
1466
    {
1467
        $this->langs->setDefaultLang('auto');
1468
        $this->langs->loadLangs(['main', 'admin', 'install', 'errors']);
1469
1470
        /**
1471
         * "main_dir"
1472
         * "main_data_dir"
1473
         * "main_url"
1474
         * "db_name"
1475
         * "db_type"
1476
         * "db_host"
1477
         * "db_port"
1478
         * "db_prefix"
1479
         * "db_user"
1480
         * "db_pass"
1481
         * "db_create_user"
1482
         * "db_create_database"
1483
         *      "db_user_root"
1484
         *      "db_pass_root"
1485
         */
1486
1487
        $this->template = 'install/db_udpate';
1488
        $this->nextButton = true;
1489
        $this->vars->errors = [];
1490
1491
        session_start(); // To be able to keep info into session (used for not losing password during navigation. The password must not transit through parameters)
1492
1493
        $oldConf = $this->config;
1494
        $this->refreshConfigFromPost();
1495
1496
        // $this->dolibarr_main_distrib = 'standard';
1497
1498
        if ($_POST['main_force_https'] ?? 'on' === 'off') {
1499
            $this->config->main->url = 'http' . substr($this->config->main->url, 5);
1500
        }
1501
1502
        $this->vars->create_database = ($_POST['db_create_database'] ?? 'off') === 'on';
1503
        $this->vars->create_user = ($_POST['db_create_user'] ?? 'off') === 'on';
1504
        $superuser = $this->vars->create_database || $this->vars->create_user;
1505
1506
        if ($superuser) {
1507
            $this->vars->root_user = getIfIsset('db_user_root', $this->vars->root_user);
1508
            $this->vars->root_pass = getIfIsset('db_pass_root', $this->vars->root_pass);
1509
1510
            $db = getDoliDBInstance(
1511
                $this->config->db->type,
1512
                $this->config->db->host,
1513
                $this->vars->root_user,
1514
                $this->vars->root_pass,
1515
                'User an database creation',
1516
                (int)$this->config->db->port
1517
            );
1518
1519
            if ($this->vars->create_database) {
1520
                $result = $db->DDLCreateDb(
1521
                    $this->config->db->name,
1522
                    $this->config->db->charset,
1523
                    $this->config->db->collation,
1524
                    $this->config->db->user
1525
                );
1526
1527
                if (!$result) {
1528
                    $this->vars->errors[] = $this->langs->trans("IfDatabaseExistsGoBackAndCheckCreate");
1529
                    return $this->doStart();
1530
                }
1531
            }
1532
1533
            if ($this->vars->create_user) {
1534
                $result = $db->DDLCreateUser(
1535
                    $this->config->db->host,
1536
                    $this->config->db->user,
1537
                    $this->config->db->pass,
1538
                    $this->config->db->name
1539
                );
1540
1541
                if ($result !== 1) {
1542
                    $this->vars->errors[] = $this->langs->trans("IfLoginDoesNotExistsCheckCreateUser");
1543
                    return $this->doStart();
1544
                }
1545
            }
1546
        }
1547
1548
        $db = getDoliDBInstance(
1549
            $this->config->db->type,
1550
            $this->config->db->host,
1551
            $this->config->db->user,
1552
            $this->config->db->pass,
1553
            $this->config->db->name,
1554
            (int)$this->config->db->port
1555
        );
1556
1557
        if (!$db->ok) {
1558
            $this->vars->errors[] = $this->langs->trans("ErrorConnection", $this->config->db->host, $this->config->db->name, $this->config->db->user);
1559
            return $this->doStart();
1560
        }
1561
1562
        return $this->write_conf_file() && Config::saveConfig() && $this->checkDatabase();
1563
    }
1564
1565
    /**
1566
     * Complete all configuration values, as received by POST.
1567
     *
1568
     * @return void
1569
     */
1570
    private function refreshConfigFromPost()
1571
    {
1572
        /**
1573
         * config:
1574
         *      "main"
1575
         *          "base_path"
1576
         *          "base_url"
1577
         *          "data_path"
1578
         *          "alt_base_path": array
1579
         *          "alt_base_url": array:1
1580
         *          "theme": "eldy"
1581
         *      "db"
1582
         *          "host"
1583
         *          "port"
1584
         *          "name"
1585
         *          "user"
1586
         *          "pass"
1587
         *          "type"
1588
         *          "prefix": "alx_"
1589
         *          "charset": "utf8"
1590
         *          "collation": "utf8_general_ci"
1591
         *          "encryption": 0
1592
         *          "cryptkey": ""
1593
         */
1594
1595
        if (!isset($this->config->main->unique_id)) {
1596
            $this->config->main->unique_id = md5(uniqid(mt_rand(), true));
1597
        }
1598
1599
        if (!isset($this->config->main->documents)) {
1600
            $this->config->main->documents = Config::getDataDir($this->config->main->path);
1601
        }
1602
1603
        $this->config->main->path = getIfIsset('base_path', $this->config->main->path);
1604
        $this->config->main->url = getIfIsset('base_url', $this->config->main->url);
1605
        $this->config->main->documents = getIfIsset('data_path', $this->config->main->documents);
1606
1607
        if ($this->force_https) {
1608
            str_replace('http://', 'https://', $this->config->main->url);
1609
        } else {
1610
            str_replace('https://', 'http://', $this->config->main->url);
1611
        }
1612
1613
        if (!isset($this->config->db)) {
1614
            $this->config->db = new stdClass();
1615
        }
1616
1617
        $this->config->db->name = getIfIsset('db_name', $this->config->db->name ?? 'alixar');
1618
        $this->config->db->type = getIfIsset('db_type', $this->config->db->type ?? '');
1619
        $this->config->db->host = getIfIsset('db_host', $this->config->db->host ?? '');
1620
        $this->config->db->port = getIfIsset('db_port', $this->config->db->port ?? '');
1621
        $this->config->db->prefix = getIfIsset('db_prefix', $this->config->db->prefix ?? Config::DEFAULT_DB_PREFIX);
1622
1623
        $this->config->db->user = getIfIsset('db_user', $this->config->db->user ?? '');
1624
        $this->config->db->pass = getIfIsset('db_pass', $this->config->db->pass ?? '');
1625
1626
        $this->config->db->charset = 'utf8';
1627
        $this->config->db->collation = 'utf8_general_ci';
1628
    }
1629
1630
    /**
1631
     * Allows to configure database access parameters.
1632
     *
1633
     * @return true
1634
     */
1635
    public function doStart(): bool
1636
    {
1637
        $this->langs->setDefaultLang('auto');
1638
        $this->langs->loadLangs(['main', 'admin', 'install']);
1639
1640
        $this->template = 'install/start';
1641
        $this->nextButton = true;
1642
1643
        /**
1644
         * There may be a file called install.forced.php with predefined parameters for the
1645
         * installation. In that case, these parameters cannot be modified. Used for guided
1646
         * installations.
1647
         *
1648
         * At the moment, we prefer not to implement this option.
1649
         *
1650
         * The best place to implement it is when creating the conf.php file, because it is
1651
         * not even necessary to install the program.
1652
         */
1653
1654
        /*
1655
        // Now we load forced values from install.forced.php file.
1656
        $useforcedwizard = false;
1657
        $forcedfile = "./install.forced.php";
1658
        if ($conffile == "/etc/dolibarr/conf.php") {
1659
            $forcedfile = "/etc/dolibarr/install.forced.php"; // Must be after inc.php
1660
        }
1661
        if (@file_exists($forcedfile)) {
1662
            $useforcedwizard = true;
1663
            include_once $forcedfile;
1664
        }
1665
        */
1666
1667
        dolibarr_install_syslog("- fileconf: entering fileconf.php page");
1668
1669
        /**
1670
         * You can force preselected values of the config step of Dolibarr by adding a file
1671
         * install.forced.php into directory htdocs/install (This is the case with some wizard
1672
         * installer like DoliWamp, DoliMamp or DoliBuntu).
1673
         * We first init "forced values" to nothing.
1674
         *
1675
         * $install_noedit empty if no block:
1676
         *   1 = To block vars specific to distrib
1677
         *   2 = To block all technical parameters
1678
         */
1679
1680
        $this->vars->install_noedit = '';
1681
1682
        $this->vars->db_types = $this->getDbTypes();
1683
1684
        $this->refreshConfigFromPost();
1685
1686
        /**
1687
         * If it is active it is 'on', if it is not active it is 'off'.
1688
         * But if it's the first time, it will be 'null', and we use it as 'on'.
1689
         */
1690
        $this->vars->force_https = ($_POST['main_force_https'] ?? 'on') === 'on';
1691
        $this->vars->create_database = ($_POST['db_create_database'] ?? 'off') === 'on';
1692
        $this->vars->create_user = ($_POST['db_create_user'] ?? 'off') === 'on';
1693
1694
        $this->vars->root_user = getIfIsset('db_user_root', $this->vars->root_user ?? '');
1695
        $this->vars->root_pass = getIfIsset('db_pass_root', $this->vars->root_pass ?? '');
1696
1697
        // session_start(); // To be able to keep info into session (used for not losing pass during navigation. pass must not transit through parameters)
1698
1699
        $this->subtitle = $this->langs->trans("ConfigurationFile");
1700
1701
        $this->nextButtonJs = 'return jscheckparam();';
1702
1703
        return true;
1704
    }
1705
1706
    /**
1707
     * Return an array with DB drivers availables (It only includes MySQL and PostgreSQL)
1708
     *
1709
     * @return array
1710
     */
1711
    private function getDbTypes()
1712
    {
1713
        $drivers = PDO::getAvailableDrivers();
1714
        foreach ($drivers as $driver) {
1715
            switch ($driver) {
1716
                case 'mysql':
1717
                    $result[] = [
1718
                        'shortname' => 'MySQL/MariaDB',
1719
                        'classname' => 'mysqli',
1720
                        'min_version' => '',
1721
                        'comment' => '',
1722
                    ];
1723
                    break;
1724
                case 'pgsql':
1725
                    $result[] = [
1726
                        'shortname' => 'PostgreSQL',
1727
                        'classname' => 'pgsql',
1728
                        'min_version' => '',
1729
                        'comment' => '',
1730
                    ];
1731
                    break;
1732
            }
1733
        }
1734
        return $result;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result seems to be defined by a foreach iteration on line 1714. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1735
    }
1736
1737
    /**
1738
     *  Save configuration file. No particular permissions are set by installer.
1739
     *
1740
     * @param string $conffile Path to conf file to generate/update
1741
     *
1742
     * @return integer
1743
     */
1744
    function write_conf_file()
1745
    {
1746
        $error = 0;
1747
1748
        $configFilename = Config::getDolibarrConfigFilename();
1749
        $key = $this->config->main->unique_id;
1750
        if (empty($key)) {
1751
            $key = md5(uniqid(mt_rand(), true)); // Generate random hash
1752
        }
1753
1754
        // $datetime = dol_print_date(dol_now(), '');
1755
        $datetime = date('Y-m-d H:i:s');
1756
1757
        $fp = fopen($configFilename, "w");
1758
        if ($fp) {
1759
            clearstatcache();
1760
1761
            fwrite($fp, '<?php' . "\n");
1762
            fwrite($fp, '//' . "\n");
1763
            fwrite($fp, '// File generated by Alixar installer ' . DOL_VERSION . ' on ' . $datetime . "\n");
1764
            fwrite($fp, '//' . "\n");
1765
            fwrite($fp, '// Take a look at conf.php.example file for an example of ' . $configFilename . ' file' . "\n");
1766
            fwrite($fp, '// and explanations for all possibles parameters.' . "\n");
1767
            fwrite($fp, '//' . "\n");
1768
1769
            fwrite($fp, '$dolibarr_main_url_root=\'' . dol_escape_php(trim($this->config->main->url), 1) . '\';');
1770
            fwrite($fp, "\n");
1771
1772
            fwrite($fp, '$dolibarr_main_document_root="' . dol_escape_php(dol_sanitizePathName(trim($this->config->main->path))) . '";');
1773
            fwrite($fp, "\n");
1774
1775
            /*
1776
            fwrite($fp, $this->main_use_alt_dir . '$dolibarr_main_url_root_alt=\'' . dol_escape_php(trim("/" . reset($this->config->main->alt_base_path)), 1) . '\';');
1777
            fwrite($fp, "\n");
1778
1779
            fwrite($fp, $this->main_use_alt_dir . '$dolibarr_main_document_root_alt="' . dol_escape_php(dol_sanitizePathName(reset(trim($this->config->main->url . "/" . $this->config->main->alt_base_url)))) . '";');
1780
            fwrite($fp, "\n");
1781
            */
1782
1783
            fwrite($fp, '$dolibarr_main_data_root="' . dol_escape_php(dol_sanitizePathName(trim($this->config->main->data_path))) . '";');
1784
            fwrite($fp, "\n");
1785
1786
            fwrite($fp, '$dolibarr_main_db_host=\'' . dol_escape_php(trim($this->config->db->host), 1) . '\';');
1787
            fwrite($fp, "\n");
1788
1789
            fwrite($fp, '$dolibarr_main_db_port=\'' . ((int)$this->config->db->port) . '\';');
1790
            fwrite($fp, "\n");
1791
1792
            fwrite($fp, '$dolibarr_main_db_name=\'' . dol_escape_php(trim($this->config->db->name), 1) . '\';');
1793
            fwrite($fp, "\n");
1794
1795
            fwrite($fp, '$dolibarr_main_db_prefix=\'' . dol_escape_php(trim($this->config->db->prefix), 1) . '\';');
1796
            fwrite($fp, "\n");
1797
1798
            fwrite($fp, '$dolibarr_main_db_user=\'' . dol_escape_php(trim($this->config->db->user), 1) . '\';');
1799
            fwrite($fp, "\n");
1800
            fwrite($fp, '$dolibarr_main_db_pass=\'' . dol_escape_php(trim($this->config->db->pass), 1) . '\';');
1801
            fwrite($fp, "\n");
1802
1803
            fwrite($fp, '$dolibarr_main_db_type=\'' . dol_escape_php(trim($this->config->db->type), 1) . '\';');
1804
            fwrite($fp, "\n");
1805
1806
            fwrite($fp, '$dolibarr_main_db_character_set=\'' . dol_escape_php(trim($this->config->db->charset), 1) . '\';');
1807
            fwrite($fp, "\n");
1808
1809
            fwrite($fp, '$dolibarr_main_db_collation=\'' . dol_escape_php(trim($this->config->db->collation), 1) . '\';');
1810
            fwrite($fp, "\n");
1811
1812
            // Authentication
1813
            fwrite($fp, '// Authentication settings');
1814
            fwrite($fp, "\n");
1815
1816
            fwrite($fp, '$dolibarr_main_authentication=\'dolibarr\';');
1817
            fwrite($fp, "\n\n");
1818
1819
            fwrite($fp, '//$dolibarr_main_demo=\'autologin,autopass\';');
1820
            fwrite($fp, "\n");
1821
1822
            fwrite($fp, '// Security settings');
1823
            fwrite($fp, "\n");
1824
1825
            fwrite($fp, '$dolibarr_main_prod=\'0\';');
1826
            fwrite($fp, "\n");
1827
1828
            fwrite($fp, '$dolibarr_main_force_https=\'' . dol_escape_php($this->config->security->force_https, 1) . '\';');
1829
            fwrite($fp, "\n");
1830
1831
            fwrite($fp, '$dolibarr_main_restrict_os_commands=\'mariadb-dump, mariadb, mysqldump, mysql, pg_dump, pgrestore, clamdscan, clamscan.exe\';');
1832
            fwrite($fp, "\n");
1833
1834
            fwrite($fp, '$dolibarr_nocsrfcheck=\'0\';');
1835
            fwrite($fp, "\n");
1836
1837
            fwrite($fp, '$dolibarr_main_instance_unique_id=\'' . dol_escape_php($key, 1) . '\';');
1838
            fwrite($fp, "\n");
1839
1840
            fwrite($fp, '$dolibarr_mailing_limit_sendbyweb=\'0\';');
1841
            fwrite($fp, "\n");
1842
            fwrite($fp, '$dolibarr_mailing_limit_sendbycli=\'0\';');
1843
            fwrite($fp, "\n");
1844
1845
            fclose($fp);
1846
1847
            if (!file_exists("$configFilename")) {
1848
                return false;
1849
            }
1850
        }
1851
1852
        return true;
1853
    }
1854
1855
    public function doAlixar()
1856
    {
1857
        header('Location: ' . BASE_URL);
1858
        die();
1859
    }
1860
}
1861