Passed
Push — main ( e2b3b9...324b47 )
by Rafael
46:15
created

InstallController::createUser()   F

Complexity

Conditions 34
Paths > 20000

Size

Total Lines 209
Code Lines 123

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 34
eloc 123
c 0
b 0
f 0
nc 207410
nop 2
dl 0
loc 209
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 modUser;
40
use PDO;
41
use stdClass;
42
43
require_once BASE_PATH . '/../Dolibarr/Lib/Admin.php';
44
require_once BASE_PATH . '/install/inc.php';
45
46
class InstallController extends DolibarrViewController
47
{
48
    /**
49
     * Set to true if we can continue with the installation
50
     *
51
     * @var bool
52
     */
53
    public bool $allow_install;
54
55
    /**
56
     * True if we want to force the use of https (recommended).
57
     *
58
     * @var bool
59
     */
60
    public bool $force_https;
61
62
    /**
63
     * It contains the html code that shows a select with the languages.
64
     *
65
     * @var string
66
     */
67
    public $selectLanguages;
68
69
    /**
70
     * It contains the html code that shows a select with the themes.
71
     *
72
     * @var string
73
     */
74
    public $selectThemes;
75
76
    /**
77
     * Contains the view subtitle
78
     *
79
     * @var string
80
     */
81
    public $subtitle;
82
83
    /**
84
     * Indicates whether to show the 'next' button.
85
     *
86
     * @var bool
87
     */
88
    public $nextButton;
89
90
    /**
91
     * Contains the JS code to be executed when the 'next' button is pressed
92
     *
93
     * @var string
94
     */
95
    public $nextButtonJs;
96
97
    /**
98
     * Multipurpose variable to send information to the view.
99
     *
100
     * @var stdClass
101
     */
102
    public $vars;
103
104
    /**
105
     * Code that is executed before the action is executed.
106
     *
107
     * @return bool
108
     */
109
    public function beforeAction(): bool
110
    {
111
        $this->vars = new stdClass();
112
113
        $https = $this->config->main->url ?? 'https';
114
        $this->force_https = (substr($https, 4, 1) === 's');
115
116
        return parent::beforeAction();
117
    }
118
119
    /**
120
     * Code that runs when "Refresh" button is pressed to set the
121
     * language and theme.
122
     *
123
     * @return bool
124
     */
125
    public function doRefresh(): bool
126
    {
127
        $this->config->main->language = getIfIsset('language', $this->config->main->language);
128
        $this->config->main->theme = getIfIsset('theme', $this->config->main->theme);
129
130
        Config::setMainConfig([
131
            'language' => $this->config->main->language,
132
            'theme' => $this->config->main->theme,
133
        ]);
134
        Config::saveConfig();
135
136
        return $this->doIndex();
137
    }
138
139
    /**
140
     * Perform a needs check for the application to determine if it meets all the
141
     * essential requirements.
142
     *
143
     * @return bool
144
     */
145
    public function doIndex(): bool
146
    {
147
        if (!isset($this->config->main->language)) {
148
            $this->config->main->language = 'auto';
149
        }
150
151
        Config::setMainConfig([
152
            'language' => getIfIsset('language', $this->config->main->language),
153
            'theme' => getIfIsset('theme', $this->config->main->theme ?? 'eldy'),
154
        ]);
155
156
        $form = new FormAdmin(null);
157
        $this->selectLanguages = $form->select_language($this->config->main->language, 'language', 1, 0, 0, 1);
158
        $this->selectThemes = $form->select_theme($this->config->main->theme);
159
160
        $this->langs->setDefaultLang($this->config->main->language);
161
        $this->langs->loadLangs(['main', 'admin', 'install']);
162
163
        $this->template = 'install/checked';
164
165
        $checks = Check::all();
166
167
        $value = $this->checkConfFile();
168
        if ($value['status'] !== Status::OK) {
169
            $checks[] = $value;
170
        }
171
172
        $conffile = Config::getDolibarrConfigFilename();
173
174
        if (!file_exists($conffile)) {
175
            $text = $this->langs->trans('YouMustCreateWithPermission', $conffile);
176
            $text .= '<br><br>';
177
            $text .= '<span class="opacitymedium">' . $this->langs->trans("CorrectProblemAndReloadPage", $_SERVER['PHP_SELF'] . '?testget=ok') . '</span>';
178
179
            $checks[] = [
180
                'status' => Status::FAIL,
181
                'text' => $text,
182
            ];
183
184
            return static::setIcons($checks);
185
        }
186
187
        $value = $this->checkIfWritable();
188
        if ($value['status'] !== Status::OK) {
189
            $checks[] = $value;
190
191
            return static::setIcons($checks);
192
        }
193
194
        /**
195
         * TODO: It is necessary to review what the next method does.
196
         */
197
        $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...
198
199
        return static::setIcons($checks);
200
    }
201
202
    /**
203
     * Ensures that the configuration file exists and can be read.
204
     *
205
     * @return array
206
     */
207
    private function checkConfFile(): array
208
    {
209
        $config_filename = Config::getDolibarrConfigFilename();
210
211
        clearstatcache();
212
        if (is_readable($config_filename) && filesize($config_filename) > 8) {
213
            $this->syslog("check: conf file '" . $config_filename . "' already defined");
214
            return ['status' => Status::OK];
215
        }
216
217
        // If not, we create it
218
        $this->syslog("check: we try to create conf file '" . $config_filename . "'");
219
220
        // First we try by copying example
221
        if (@copy($config_filename . ".example", $config_filename)) {
222
            // Success
223
            $this->syslog("check: successfully copied file " . $config_filename . ".example into " . $config_filename);
224
            return ['status' => Status::OK];
225
        }
226
227
        // If failed, we try to create an empty file
228
        $this->syslog("check: failed to copy file " . $config_filename . ".example into " . $config_filename . ". We try to create it.", LOG_WARNING);
229
230
        $fp = @fopen($config_filename, "w");
231
        if ($fp) {
232
            @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

232
            /** @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...
233
            @fwrite($fp, "\n");
234
            if (fclose($fp)) {
235
                return ['status' => Status::OK];
236
            }
237
        }
238
239
        $this->syslog("check: failed to create a new file " . $config_filename . " into current dir " . getcwd() . ". Please check permissions.", LOG_ERR);
240
        return [
241
            'status' => Status::FAIL,
242
            'text' => $this->langs->trans('ConfFileDoesNotExistsAndCouldNotBeCreated', 'conf.php')
243
        ];
244
    }
245
246
    /**
247
     * Returns an array with the checks carried out, indicating the
248
     * name of the action, if there is an error and the icon to display.
249
     *
250
     * @param array $checks
251
     * @return bool
252
     */
253
    private function setIcons(array $checks): bool
254
    {
255
        $ok = true;
256
        $this->vars->checks = [];
257
        foreach ($checks as $check) {
258
            if (!isset($check['text'])) {
259
                continue;
260
            }
261
            $value = [];
262
            $value['text'] = $check['text'];
263
            switch ($check['status']) {
264
                case Status::OK:
265
                    $value['ok'] = true;
266
                    $value['icon'] = 'tick';
267
                    break;
268
                case Status::WARNING:
269
                    $value['ok'] = true;
270
                    $value['icon'] = 'warning';
271
                    break;
272
                case Status::FAIL:
273
                    $value['ok'] = false;
274
                    $value['icon'] = 'error';
275
                    $ok = false;
276
            }
277
            $this->vars->checks[] = $value;
278
        }
279
280
        if (!$ok) {
281
            $this->vars->checks[] = [
282
                'ok' => false,
283
                'icon' => 'error',
284
                'text' => $this->langs->trans('ErrorGoBackAndCorrectParameters'),
285
            ];
286
        }
287
288
        return $ok;
289
    }
290
291
    /**
292
     * Checks if the configuration file can be edited.
293
     *
294
     * @return array
295
     */
296
    private function checkIfWritable()
297
    {
298
        $config_filename = Config::getDolibarrConfigFilename();
299
300
        if (is_dir($config_filename)) {
301
            return [
302
                'status' => Status::FAIL,
303
                'text' => $this->langs->trans('ConfFileMustBeAFileNotADir', $config_filename),
304
            ];
305
        }
306
307
        $this->allow_install = is_writable($config_filename);
308
        if (!$this->allow_install) {
309
            return [
310
                'status' => Status::FAIL,
311
                'text' => $this->langs->trans('ConfFileIsNotWritable', $config_filename),
312
            ];
313
        }
314
315
        return [
316
            'status' => Status::OK,
317
        ];
318
    }
319
320
    /**
321
     * Fill in the information about the options available to install and/or update.
322
     * TODO: This method needs major refactoring
323
     *
324
     * @return void
325
     * @throws \Exception
326
     */
327
    private function next()
328
    {
329
        $configFilename = Config::getDolibarrConfigFilename();
330
        $conf = Config::getConf();
331
        $config = Config::getConfig($conf);
332
333
        $ok = false;
334
        if (!empty($config->main_db_type) && !empty($config->main_document_root)) {
335
            $this->errorBadMainDocumentRoot = '';
336
            if ($config->main_document_root !== BASE_PATH) {
337
                $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.";
338
                dol_syslog($this->errorBadMainDocumentRoot, LOG_WARNING);
339
            } else {
340
                // If password is encoded, we decode it
341
                // TODO: Pending
342
                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...
343
                    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...
344
                    if (preg_match('/crypted:/i', $config->main_db_pass)) {
345
                        $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
346
                        $config->main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
347
                    } else {
348
                        $config->main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
349
                    }
350
                }
351
352
                // $conf already created in inc.php
353
                $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...
354
                $this->conf->db->host = $config->main_db_host;
355
                $this->conf->db->port = $config->main_db_port;
356
                $this->conf->db->name = $config->main_db_name;
357
                $this->conf->db->user = $config->main_db_user;
358
                $this->conf->db->pass = $config->main_db_pass;
359
                $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);
360
                if ($db->connected && $db->database_selected) {
361
                    $ok = true;
362
                }
363
            }
364
        }
365
366
        $this->vars->availableChoices = [];
367
        $this->vars->notAvailableChoices = [];
368
369
        // If database access is available, we set more variables
370
        // TODO: Pending
371
        if ($ok) {
372
            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...
373
                $dolibarr_main_db_encryption = 0;
374
            }
375
            $this->conf->db->dolibarr_main_db_encryption = $dolibarr_main_db_encryption;
376
            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...
377
                $dolibarr_main_db_cryptkey = '';
378
            }
379
            $this->conf->db->dolibarr_main_db_cryptkey = $dolibarr_main_db_cryptkey;
380
381
            $this->conf->setValues($db);
382
            // Reset forced setup after the setValues
383
            if (defined('SYSLOG_FILE')) {
384
                $this->conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
385
            }
386
            $this->conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
387
388
            // Current version is $this->conf->global->MAIN_VERSION_LAST_UPGRADE
389
            // Version to install is DOL_VERSION
390
            $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 : ''));
391
            $dolibarrversiontoinstallarray = versiondolibarrarray();
392
        }
393
394
        $this->vars->printVersion = getDolGlobalString('MAIN_VERSION_LAST_UPGRADE') || getDolGlobalString('MAIN_VERSION_LAST_INSTALL');
395
396
        $foundrecommandedchoice = 0;
397
398
        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...
399
            $foundrecommandedchoice = 1; // To show only once
400
        }
401
402
        /*
403
        $button = $this->allow_install
404
            ? '<input class="button" type="submit" name="action" value="' . $this->langs->trans("Start") . '">'
405
            : ($foundrecommandedchoice ? '<span class="warning">' : '') . $this->langs->trans("InstallNotAllowed") . ($foundrecommandedchoice ? '</span>' : '');
406
        */
407
408
        // TODO: We have to see how we can use the action, and that the text is displayed in the correct language
409
        $button = $this->allow_install
410
            ? '<input class="button" type="submit" name="action" value="start">' . $this->langs->trans("Start")
411
            : ($foundrecommandedchoice ? '<span class="warning">' : '') . $this->langs->trans("InstallNotAllowed") . ($foundrecommandedchoice ? '</span>' : '');
412
413
        // Show line of first install choice
414
        $choice = [
415
            'selected' => true,
416
            'short' => $this->langs->trans("FreshInstall"),
417
            'long' => $this->langs->trans("FreshInstallDesc"),
418
            'active' => $this->allow_install,
419
            'button' => $button,
420
        ];
421
422
        if (!isset($config->main_db_host) || empty($config->main_db_host)) {
423
            $choice['long'] .= '<br><div class="center"><div class="ok suggestedchoice">' . $this->langs->trans("InstallChoiceSuggested") . '</div></div>';
424
        }
425
426
        $this->vars->availableChoices[] = $choice;
427
428
        $positionkey = ($foundrecommandedchoice ? 999 : 0);
429
        if ($this->allow_install) {
430
            $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...
431
        } else {
432
            $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...
433
        }
434
435
        // Show upgrade lines
436
        $allowupgrade = true;
437
        if (empty($config->main_db_host)) {    // This means install process was not run
438
            $allowupgrade = false;
439
        }
440
        if (getDolGlobalInt("MAIN_NOT_INSTALLED")) {
441
            $allowupgrade = false;
442
        }
443
        if (GETPOST('allowupgrade')) {
444
            $allowupgrade = true;
445
        }
446
447
        $this->vars->errorMigrations = false;
448
        $migrationscript = $this->getMigrationScript();
449
450
        $count = 0;
451
        foreach ($migrationscript as $migarray) {
452
            $choice = '';
453
454
            $count++;
455
            $recommended_choice = false;
456
            $version = DOL_VERSION;
457
            $versionfrom = $migarray['from'];
458
            $versionto = $migarray['to'];
459
            $versionarray = preg_split('/[\.-]/', $version);
460
            $dolibarrversionfromarray = preg_split('/[\.-]/', $versionfrom);
461
            $dolibarrversiontoarray = preg_split('/[\.-]/', $versionto);
462
            // Define string newversionxxx that are used for text to show
463
            $newversionfrom = preg_replace('/(\.[0-9]+)$/i', '.*', $versionfrom);
464
            $newversionto = preg_replace('/(\.[0-9]+)$/i', '.*', $versionto);
465
            $newversionfrombis = '';
466
            if (versioncompare($dolibarrversiontoarray, $versionarray) < -2) {  // From x.y.z -> x.y.z+1
467
                $newversionfrombis = ' ' . $this->langs->trans("or") . ' ' . $versionto;
468
            }
469
470
            if ($ok) {
471
                if (count($dolibarrlastupgradeversionarray) >= 2) { // If database access is available and last upgrade version is known
472
                    // Now we check if this is the first qualified choice
473
                    if (
474
                        $allowupgrade && empty($foundrecommandedchoice) &&
475
                        (versioncompare($dolibarrversiontoarray, $dolibarrlastupgradeversionarray) > 0 || versioncompare($dolibarrversiontoarray, $versionarray) < -2)
476
                    ) {
477
                        $foundrecommandedchoice = 1; // To show only once
478
                        $recommended_choice = true;
479
                    }
480
                } else {
481
                    // We cannot recommend a choice.
482
                    // A version of install may be known, but we need last upgrade.
483
                }
484
            }
485
486
            $button = $this->langs->trans("NotAvailable");
487
            if ($allowupgrade) {
488
                $disabled = false;
489
                if ($foundrecommandedchoice == 2) {
490
                    $disabled = true;
491
                }
492
                if ($foundrecommandedchoice == 1) {
493
                    $foundrecommandedchoice = 2;
494
                }
495
                if ($disabled) {
496
                    $button = '<span class="opacitymedium">' . $this->langs->trans("NotYetAvailable") . '</span>';
497
                } else {
498
                    // TODO: Pending fix how to pass the version in an action
499
                    $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>';
500
                }
501
            }
502
503
            $choice = [
504
                'selected' => $recommended_choice,
505
                'short' => $this->langs->trans("Upgrade") . '<br>' . $newversionfrom . $newversionfrombis . ' -> ' . $newversionto,
506
                'long' => $this->langs->trans("UpgradeDesc"),
507
                'active' => $this->allow_install,
508
                'button' => $button,
509
            ];
510
511
            if ($recommended_choice) {
512
                $choice['long'] .= '<br><div class="center"><div class="ok suggestedchoice">' . $this->langs->trans("InstallChoiceSuggested") . '</div>';
513
                if ($count < count($migarray)) {
514
                    $choice['long'] .= $this->langs->trans('MigrateIsDoneStepByStep', DOL_VERSION);
515
                }
516
                $choice['long'] .= '</div>';
517
            }
518
519
            if ($allowupgrade) {
520
                $this->vars->availableChoices[$count] = $choice;
521
            } else {
522
                $this->vars->notAvailableChoices[$count] = $choice;
523
            }
524
        }
525
526
        // If there is no choice at all, we show all of them.
527
        if (empty($this->vars->availableChoices)) {
528
            $this->vars->availableChoices = $this->vars->notAvailableChoices;
529
            $this->vars->notAvailableChoices = [];
530
        }
531
532
        // Array of install choices
533
        krsort($this->vars->availableChoices, SORT_NATURAL);
534
    }
535
536
    /**
537
     * Gets an array with the SQL scripts for updating the database.
538
     * TODO: This method needs major refactoring
539
     *
540
     * @return array|mixed[]
541
     */
542
    private function getMigrationScript()
543
    {
544
        $dir = BASE_PATH . "/../Dolibarr/Modules/Install/mysql/migration/";   // We use mysql migration scripts whatever is database driver
545
        dolibarr_install_syslog("Scan sql files for migration files in " . $dir);
546
547
        // Get files list of migration file x.y.z-a.b.c.sql into /install/mysql/migration
548
        $migrationscript = [];
549
        $handle = opendir($dir);
550
        if (!is_resource($handle)) {
551
            $this->vars->errorMigrations = $this->langs->trans("ErrorCanNotReadDir", $dir);
552
            return [];
553
        }
554
555
        $versiontousetoqualifyscript = preg_replace('/-.*/', '', DOL_VERSION);
556
        while (($file = readdir($handle)) !== false) {
557
            $reg = [];
558
            if (preg_match('/^(\d+\.\d+\.\d+)-(\d+\.\d+\.\d+)\.sql$/i', $file, $reg)) {
559
                //var_dump(DOL_VERSION." ".$reg[2]." ".$versiontousetoqualifyscript." ".version_compare($versiontousetoqualifyscript, $reg[2]));
560
                if (!empty($reg[2]) && version_compare($versiontousetoqualifyscript, $reg[2]) >= 0) {
561
                    $migrationscript[] = ['from' => $reg[1], 'to' => $reg[2]];
562
                }
563
            }
564
        }
565
        return dol_sort_array($migrationscript, 'from', 'asc', 1);
566
    }
567
568
    public function doCreateAdminUser()
569
    {
570
        $this->langs->setDefaultLang($this->config->main->language);
571
        $this->langs->loadLangs(['main', 'admin', 'install']);
572
573
        $this->subtitle = $this->langs->trans("AdminAccountCreation");
574
        $this->template = 'install/create_admin_user';
575
576
        /*
577
        // Now we load forced value from install.forced.php file.
578
        $useforcedwizard = false;
579
        $forcedfile = "./install.forced.php";
580
        if ($conffile == "/etc/dolibarr/conf.php") {
581
            $forcedfile = "/etc/dolibarr/install.forced.php";
582
        }
583
        if (@file_exists($forcedfile)) {
584
            $useforcedwizard = true;
585
            include_once $forcedfile;
586
        }
587
        */
588
589
        dolibarr_install_syslog("--- step4: entering step4.php page");
590
591
        $this->vars->minLen = 8;
592
        $this->vars->login = (GETPOSTISSET("login")
593
            ? GETPOST("login", 'alpha')
594
            : (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...
595
                ? $force_install_dolibarrlogin
596
                : ''
597
            ));
598
599
        $this->nextButton = true;
600
    }
601
602
    public function doVerifyAdminUser()
603
    {
604
        $this->langs->setDefaultLang($this->config->main->language);
605
        $this->langs->loadLangs(['main', 'admin', 'install']);
606
607
        $this->vars->login = GETPOST('login');
608
        $this->vars->pass = GETPOST('pass');
609
        $this->vars->pass_verif = GETPOST('pass_verif');
610
        $this->vars->minLen = 8;
611
612
        $this->nextButton = true;
613
614
        $this->vars->errors = [];
615
616
        if (empty($this->vars->login)) {
617
            $this->vars->errors[] = $this->langs->trans("PleaseTypeALogin");
618
        }
619
620
        if (strlen($this->vars->pass) < $this->vars->minLen) {
621
            $this->vars->errors[] = $this->langs->trans("PleaseTypePassword");
622
        }
623
624
        if ($this->vars->pass !== $this->vars->pass_verif) {
625
            $this->vars->errors[] = $this->langs->trans("PasswordsMismatch");
626
        }
627
628
        if (!empty($this->vars->errors)) {
629
            $this->template = 'install/create_admin_user';
630
            return false;
631
        }
632
633
        if (!$this->createUser($this->vars->login, $this->vars->pass)) {
634
            $this->template = 'install/create_admin_user';
635
            return false;
636
        }
637
638
        $this->template = 'install/finish';
639
        return true;
640
641
        $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...
642
643
644
        $error = 0;
645
        $ok = 0;
646
647
        $this->vars->config_read_only = !is_writable($conffile);
648
649
        $db = getDoliDBInstance(
650
            $this->config->db->type,
651
            $this->config->db->host,
652
            $this->config->db->user,
653
            $this->config->db->pass,
654
            $this->config->db->name,
655
            (int)$this->config->db->port
656
        );
657
658
        dolibarr_install_syslog("Exit " . $ret);
659
660
        dolibarr_install_syslog("--- step4: end");
661
662
        return true;
663
    }
664
665
    private function createUser(string $username, string $password): bool
666
    {
667
        $db = Config::getDb();
668
        $conf = Config::getConf();
669
670
        // Active module user
671
        include_once BASE_PATH . '/core/modules/modUser.class.php';
672
        $objMod = new modUser($db);
673
674
        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...
675
        $result = $objMod->init();
676
        if (!$result) {
677
            print "ERROR: failed to init module file = " . $file;
678
        }
679
680
        if ($db->connected) {
681
            $conf->setValues($db);
682
            // Reset forced setup after the setValues
683
            if (defined('SYSLOG_FILE')) {
684
                $conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
685
            }
686
            $conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
687
688
            // Create admin user
689
            include_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
690
691
            // Set default encryption to yes, generate a salt and set default encryption algorithm (but only if there is no user yet into database)
692
            $sql = "SELECT u.rowid, u.pass, u.pass_crypted";
693
            $sql .= " FROM " . MAIN_DB_PREFIX . "user as u";
694
            $resql = $db->query($sql);
695
            if ($resql) {
696
                $numrows = $db->num_rows($resql);
697
                if ($numrows == 0) {
698
                    // Define default setup for password encryption
699
                    dolibarr_set_const($db, "DATABASE_PWD_ENCRYPTED", "1", 'chaine', 0, '', $conf->entity);
700
                    dolibarr_set_const($db, "MAIN_SECURITY_SALT", dol_print_date(dol_now(), 'dayhourlog'), 'chaine', 0, '', 0); // All entities
701
                    if (function_exists('password_hash')) {
702
                        dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'password_hash', 'chaine', 0, '', 0); // All entities
703
                    } else {
704
                        dolibarr_set_const($db, "MAIN_SECURITY_HASH_ALGO", 'sha1md5', 'chaine', 0, '', 0); // All entities
705
                    }
706
                }
707
708
                dolibarr_install_syslog('step5: DATABASE_PWD_ENCRYPTED = ' . getDolGlobalString('DATABASE_PWD_ENCRYPTED') . ' MAIN_SECURITY_HASH_ALGO = ' . getDolGlobalString('MAIN_SECURITY_HASH_ALGO'), LOG_INFO);
709
            }
710
711
            // Create user used to create the admin user
712
            $createuser = new User($db);
713
            $createuser->id = 0;
714
            $createuser->admin = 1;
715
716
            // Set admin user
717
            $newuser = new User($db);
718
            $newuser->lastname = 'SuperAdmin';
719
            $newuser->firstname = '';
720
            $newuser->login = $username;
721
            $newuser->pass = $password;
722
            $newuser->admin = 1;
723
            $newuser->entity = 0;
724
725
            $conf->global->USER_MAIL_REQUIRED = 0;            // Force global option to be sure to create a new user with no email
726
            $conf->global->USER_PASSWORD_GENERATED = '';    // To not use any rule for password validation
727
728
            $result = $newuser->create($createuser, 1);
729
            if ($result > 0) {
730
                print $this->langs->trans("AdminLoginCreatedSuccessfuly", $login) . "<br>";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $login seems to be never defined.
Loading history...
731
                $success = 1;
732
            } else {
733
                if ($result == -6) {    //login or email already exists
734
                    dolibarr_install_syslog('step5: AdminLoginAlreadyExists', LOG_WARNING);
735
                    print '<br><div class="warning">' . $newuser->error . "</div><br>";
736
                    $success = 1;
737
                } else {
738
                    dolibarr_install_syslog('step5: FailedToCreateAdminLogin ' . $newuser->error, LOG_ERR);
739
                    setEventMessages($this->langs->trans("FailedToCreateAdminLogin") . ' ' . $newuser->error, null, 'errors');
740
                    //header("Location: step4.php?error=3&selectlang=$setuplang".(isset($login) ? '&login='.$login : ''));
741
                    print '<br><div class="error">' . $this->langs->trans("FailedToCreateAdminLogin") . ': ' . $newuser->error . '</div><br><br>';
742
                    print $this->langs->trans("ErrorGoBackAndCorrectParameters") . '<br><br>';
743
                }
744
            }
745
746
            if ($success) {
747
                // 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.
748
                $db->begin();
749
                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...
750
                $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)");
751
                if ($resql) {
752
                    $conf->global->MAIN_VERSION_FIRST_INSTALL = $targetversion;
753
                    $db->commit();
754
                } else {
755
                    //if (! $resql) dol_print_error($db,'Error in setup program');      // We ignore errors. Key may already exists
756
                    $db->commit();
757
                }
758
759
                $db->begin();
760
761
                dolibarr_install_syslog('step5: set MAIN_VERSION_LAST_INSTALL const to ' . $targetversion, LOG_DEBUG);
762
                $resql = $db->query("DELETE FROM " . MAIN_DB_PREFIX . "const WHERE " . $db->decrypt('name') . " = 'MAIN_VERSION_LAST_INSTALL'");
763
                if (!$resql) {
764
                    dol_print_error($db, 'Error in setup program');
765
                }
766
                $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)");
767
                if (!$resql) {
768
                    dol_print_error($db, 'Error in setup program');
769
                }
770
                $conf->global->MAIN_VERSION_LAST_INSTALL = $targetversion;
771
772
                if ($useforcedwizard) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $useforcedwizard seems to be never defined.
Loading history...
773
                    dolibarr_install_syslog('step5: set MAIN_REMOVE_INSTALL_WARNING const to 1', LOG_DEBUG);
774
                    $resql = $db->query("DELETE FROM " . MAIN_DB_PREFIX . "const WHERE " . $db->decrypt('name') . " = 'MAIN_REMOVE_INSTALL_WARNING'");
775
                    if (!$resql) {
776
                        dol_print_error($db, 'Error in setup program');
777
                    }
778
                    // 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
779
                    /* No need to enable this
780
                    $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)");
781
                    if (!$resql) {
782
                        dol_print_error($db, 'Error in setup program');
783
                    }
784
                    $conf->global->MAIN_REMOVE_INSTALL_WARNING = 1;
785
                    */
786
                }
787
788
                // List of modules to enable
789
                $tmparray = array();
790
791
                // If we ask to force some modules to be enabled
792
                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...
793
                    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...
794
                        define('DOL_DOCUMENT_ROOT', $dolibarr_main_document_root);
795
                    }
796
797
                    $tmparray = explode(',', $force_install_module);
798
                }
799
800
                $modNameLoaded = array();
801
802
                // Search modules dirs
803
                $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...
804
805
                foreach ($modulesdir as $dir) {
806
                    // Load modules attributes in arrays (name, numero, orders) from dir directory
807
                    //print $dir."\n<br>";
808
                    dol_syslog("Scan directory " . $dir . " for module descriptor files (modXXX.class.php)");
809
                    $handle = @opendir($dir);
810
                    if (is_resource($handle)) {
811
                        while (($file = readdir($handle)) !== false) {
812
                            if (is_readable($dir . $file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') {
813
                                $modName = substr($file, 0, dol_strlen($file) - 10);
814
                                if ($modName) {
815
                                    if (!empty($modNameLoaded[$modName])) {   // In cache of already loaded modules ?
816
                                        $mesg = "Error: Module " . $modName . " was found twice: Into " . $modNameLoaded[$modName] . " and " . $dir . ". You probably have an old file on your disk.<br>";
817
                                        setEventMessages($mesg, null, 'warnings');
818
                                        dol_syslog($mesg, LOG_ERR);
819
                                        continue;
820
                                    }
821
822
                                    try {
823
                                        $res = include_once $dir . $file; // A class already exists in a different file will send a non catchable fatal error.
824
                                        if (class_exists($modName)) {
825
                                            $objMod = new $modName($db);
826
                                            $modNameLoaded[$modName] = $dir;
827
                                            if (!empty($objMod->enabled_bydefault) && !in_array($file, $tmparray)) {
828
                                                $tmparray[] = $file;
829
                                            }
830
                                        }
831
                                    } 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...
832
                                        dol_syslog("Failed to load " . $dir . $file . " " . $e->getMessage(), LOG_ERR);
833
                                    }
834
                                }
835
                            }
836
                        }
837
                    }
838
                }
839
840
                // Loop on each modules to activate it
841
                if (!empty($tmparray)) {
842
                    foreach ($tmparray as $modtoactivate) {
843
                        $modtoactivatenew = preg_replace('/\.class\.php$/i', '', $modtoactivate);
844
                        //print $this->langs->trans("ActivateModule", $modtoactivatenew).'<br>';
845
846
                        $file = $modtoactivatenew . '.class.php';
847
                        dolibarr_install_syslog('step5: activate module file=' . $file);
848
                        $res = dol_include_once("/core/modules/" . $file);
849
850
                        $res = activateModule($modtoactivatenew, 1);
851
                        if (!empty($res['errors'])) {
852
                            print 'ERROR: failed to activateModule() file=' . $file;
853
                        }
854
                    }
855
                    //print '<br>';
856
                }
857
858
                // Now delete the flag that say installation is not complete
859
                dolibarr_install_syslog('step5: remove MAIN_NOT_INSTALLED const');
860
                $resql = $db->query("DELETE FROM " . MAIN_DB_PREFIX . "const WHERE " . $db->decrypt('name') . " = 'MAIN_NOT_INSTALLED'");
861
                if (!$resql) {
862
                    dol_print_error($db, 'Error in setup program');
863
                }
864
865
                // May fail if parameter already defined
866
                dolibarr_install_syslog('step5: set the default language');
867
                $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...
868
                //if (! $resql) dol_print_error($db,'Error in setup program');
869
870
                $db->commit();
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
871
            }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 746 is false. This is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
872
        } else {
873
            print $this->langs->trans("ErrorFailedToConnect") . "<br>";
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
874
        }
875
    }
876
877
    public function checkDatabase()
878
    {
879
        if (isset($_POST['return'])) {
880
            return $this->doConfig();
881
        }
882
883
        $ok = 0;
884
885
        $this->template = 'install/db_update';
886
        $this->subtitle = $this->langs->trans("CreateDatabaseObjects");
887
        $this->nextButton = true;
888
889
// This page can be long. We increase the time allowed. / Cette page peut etre longue. On augmente le delai autorise.
890
// Only works if you are not in safe_mode. / Ne fonctionne que si on est pas en safe_mode.
891
892
        $err = error_reporting();
893
        error_reporting(0);      // Disable all errors
894
//error_reporting(E_ALL);
895
        @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

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