1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * This script creates config.php file and prepares database.
20 *
21 * This script is not intended for beginners!
22 * Potential problems:
23 * - su to apache account or sudo before execution
24 * - not compatible with Windows platform
25 *
26 * @package    core
27 * @subpackage cli
28 * @copyright  2009 Petr Skoda (http://skodak.org)
29 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30 */
31
32define('CLI_SCRIPT', true);
33
34// extra execution prevention - we can not just require config.php here
35if (isset($_SERVER['REMOTE_ADDR'])) {
36    exit(1);
37}
38
39// Force OPcache reset if used, we do not want any stale caches
40// when preparing test environment.
41if (function_exists('opcache_reset')) {
42    opcache_reset();
43}
44
45$help =
46"Command line Moodle installer, creates config.php and initializes database.
47Please note you must execute this script with the same uid as apache
48or use chmod/chown after installation.
49
50Site defaults may be changed via local/defaults.php.
51
52Options:
53--chmod=OCTAL-MODE    Permissions of new directories created within dataroot.
54                      Default is 2777. You may want to change it to 2770
55                      or 2750 or 750. See chmod man page for details.
56--lang=CODE           Installation and default site language.
57--wwwroot=URL         Web address for the Moodle site,
58                      required in non-interactive mode.
59--dataroot=DIR        Location of the moodle data folder,
60                      must not be web accessible. Default is moodledata
61                      in the parent directory.
62--dbtype=TYPE         Database type. Default is mysqli
63--dbhost=HOST         Database host. Default is localhost
64--dbname=NAME         Database name. Default is moodle
65--dbuser=USERNAME     Database user. Default is root
66--dbpass=PASSWORD     Database password. Default is blank
67--dbport=NUMBER       Use database port.
68--dbsocket=PATH       Use database socket, 1 means default. Available for some databases only.
69--prefix=STRING       Table prefix for above database tables. Default is mdl_
70--fullname=STRING     The fullname of the site
71--shortname=STRING    The shortname of the site
72--summary=STRING      The summary to be displayed on the front page
73--adminuser=USERNAME  Username for the moodle admin account. Default is admin
74--adminpass=PASSWORD  Password for the moodle admin account,
75                      required in non-interactive mode.
76--adminemail=STRING   Email address for the moodle admin account.
77--upgradekey=STRING   The upgrade key to be set in the config.php, leave empty to not set it.
78--non-interactive     No interactive questions, installation fails if any
79                      problem encountered.
80--agree-license       Indicates agreement with software license,
81                      required in non-interactive mode.
82--allow-unstable      Install even if the version is not marked as stable yet,
83                      required in non-interactive mode.
84--skip-database       Stop the installation before installing the database.
85-h, --help            Print out this help
86
87Example:
88\$sudo -u www-data /usr/bin/php admin/cli/install.php --lang=cs
89"; //TODO: localize, mark as needed in install - to be translated later when everything is finished
90
91
92// distro specific customisation
93$distrolibfile = __DIR__.'/../../install/distrolib.php';
94$distro = null;
95if (file_exists($distrolibfile)) {
96    require_once($distrolibfile);
97    if (function_exists('distro_get_config')) {
98        $distro = distro_get_config();
99    }
100}
101
102// Nothing to do if config.php exists
103$configfile = __DIR__.'/../../config.php';
104if (file_exists($configfile)) {
105    require($configfile);
106    require_once($CFG->libdir.'/clilib.php');
107    list($options, $unrecognized) = cli_get_params(array('help'=>false), array('h'=>'help'));
108
109    if ($options['help']) {
110        echo $help;
111        echo "\n\n";
112    }
113
114    if ($DB->get_manager()->table_exists('config')) {
115        cli_error(get_string('clialreadyinstalled', 'install'));
116    } else {
117        cli_error(get_string('clialreadyconfigured', 'install'));
118    }
119}
120
121$olddir = getcwd();
122
123// change directory so that includes below work properly
124chdir(dirname($_SERVER['argv'][0]));
125
126// Servers should define a default timezone in php.ini, but if they don't then make sure something is defined.
127if (!function_exists('date_default_timezone_set') or !function_exists('date_default_timezone_get')) {
128    fwrite(STDERR, "Timezone functions are not available.\n");
129    exit(1);
130}
131date_default_timezone_set(@date_default_timezone_get());
132
133// make sure PHP errors are displayed - helps with diagnosing of problems
134@error_reporting(E_ALL);
135@ini_set('display_errors', '1');
136// we need a lot of memory
137@ini_set('memory_limit', '128M');
138
139/** Used by library scripts to check they are being called by Moodle */
140define('MOODLE_INTERNAL', true);
141
142// Disables all caching.
143define('CACHE_DISABLE_ALL', true);
144
145define('PHPUNIT_TEST', false);
146
147define('IGNORE_COMPONENT_CACHE', true);
148
149// Check that PHP is of a sufficient version as soon as possible.
150require_once(__DIR__.'/../../lib/phpminimumversionlib.php');
151moodle_require_minimum_php_version();
152
153// set up configuration
154global $CFG;
155$CFG = new stdClass();
156$CFG->lang                 = 'en';
157$CFG->dirroot              = dirname(dirname(__DIR__));
158$CFG->libdir               = "$CFG->dirroot/lib";
159$CFG->wwwroot              = "http://localhost";
160$CFG->httpswwwroot         = $CFG->wwwroot;
161$CFG->docroot              = 'http://docs.moodle.org';
162$CFG->running_installer    = true;
163$CFG->early_install_lang   = true;
164$CFG->ostype               = (stristr(PHP_OS, 'win') && !stristr(PHP_OS, 'darwin')) ? 'WINDOWS' : 'UNIX';
165$CFG->dboptions            = array();
166$CFG->debug                = (E_ALL | E_STRICT);
167$CFG->debugdisplay         = true;
168$CFG->debugdeveloper       = true;
169
170$parts = explode('/', str_replace('\\', '/', dirname(__DIR__)));
171$CFG->admin                = array_pop($parts);
172
173//point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else
174//the problem is that we need specific version of quickforms and hacked excel files :-(
175ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path'));
176
177require_once($CFG->libdir.'/classes/component.php');
178require_once($CFG->libdir.'/classes/text.php');
179require_once($CFG->libdir.'/classes/string_manager.php');
180require_once($CFG->libdir.'/classes/string_manager_install.php');
181require_once($CFG->libdir.'/classes/string_manager_standard.php');
182require_once($CFG->libdir.'/installlib.php');
183require_once($CFG->libdir.'/clilib.php');
184require_once($CFG->libdir.'/setuplib.php');
185require_once($CFG->libdir.'/weblib.php');
186require_once($CFG->libdir.'/dmllib.php');
187require_once($CFG->libdir.'/moodlelib.php');
188require_once($CFG->libdir.'/deprecatedlib.php');
189require_once($CFG->libdir.'/adminlib.php');
190require_once($CFG->libdir.'/componentlib.class.php');
191require_once($CFG->dirroot.'/cache/lib.php');
192
193// Register our classloader, in theory somebody might want to replace it to load other hacked core classes.
194// Required because the database checks below lead to session interaction which is going to lead us to requiring autoloaded classes.
195if (defined('COMPONENT_CLASSLOADER')) {
196    spl_autoload_register(COMPONENT_CLASSLOADER);
197} else {
198    spl_autoload_register('core_component::classloader');
199}
200
201require($CFG->dirroot.'/version.php');
202$CFG->target_release = $release;
203
204\core\session\manager::init_empty_session();
205global $SESSION;
206global $USER;
207
208global $COURSE;
209$COURSE = new stdClass();
210$COURSE->id = 1;
211
212global $SITE;
213$SITE = $COURSE;
214define('SITEID', 1);
215
216//Database types
217$databases = array('mysqli' => moodle_database::get_driver_instance('mysqli', 'native'),
218                   'auroramysql' => moodle_database::get_driver_instance('auroramysql', 'native'),
219                   'mariadb'=> moodle_database::get_driver_instance('mariadb', 'native'),
220                   'pgsql'  => moodle_database::get_driver_instance('pgsql',  'native'),
221                   'oci'    => moodle_database::get_driver_instance('oci',    'native'),
222                   'sqlsrv' => moodle_database::get_driver_instance('sqlsrv', 'native'), // MS SQL*Server PHP driver
223                  );
224foreach ($databases as $type=>$database) {
225    if ($database->driver_installed() !== true) {
226        unset($databases[$type]);
227    }
228}
229if (empty($databases)) {
230    $defaultdb = '';
231} else {
232    reset($databases);
233    $defaultdb = key($databases);
234}
235
236// now get cli options
237list($options, $unrecognized) = cli_get_params(
238    array(
239        'chmod'             => isset($distro->directorypermissions) ? sprintf('%04o',$distro->directorypermissions) : '2777', // let distros set dir permissions
240        'lang'              => $CFG->lang,
241        'wwwroot'           => '',
242        'dataroot'          => empty($distro->dataroot) ? str_replace('\\', '/', dirname(dirname(dirname(__DIR__))).'/moodledata'): $distro->dataroot, // initialised later after including libs or by distro
243        'dbtype'            => empty($distro->dbtype) ? $defaultdb : $distro->dbtype, // let distro skip dbtype selection
244        'dbhost'            => empty($distro->dbhost) ? 'localhost' : $distro->dbhost, // let distros set dbhost
245        'dbname'            => 'moodle',
246        'dbuser'            => empty($distro->dbuser) ? 'root' : $distro->dbuser, // let distros set dbuser
247        'dbpass'            => '',
248        'dbport'            => '',
249        'dbsocket'          => '',
250        'prefix'            => 'mdl_',
251        'fullname'          => '',
252        'shortname'         => '',
253        'summary'           => '',
254        'adminuser'         => 'admin',
255        'adminpass'         => '',
256        'adminemail'        => '',
257        'upgradekey'        => '',
258        'non-interactive'   => false,
259        'agree-license'     => false,
260        'allow-unstable'    => false,
261        'skip-database'     => false,
262        'help'              => false
263    ),
264    array(
265        'h' => 'help'
266    )
267);
268
269$interactive = empty($options['non-interactive']);
270$skipdatabase = $options['skip-database'];
271
272// set up language
273$lang = clean_param($options['lang'], PARAM_SAFEDIR);
274$languages = get_string_manager()->get_list_of_translations();
275if (array_key_exists($lang, $languages)) {
276    $CFG->lang = $lang;
277}
278
279if ($unrecognized) {
280    $unrecognized = implode("\n  ", $unrecognized);
281    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
282}
283
284if ($options['help']) {
285    echo $help;
286    die;
287}
288
289//Print header
290cli_logo();
291echo PHP_EOL;
292echo get_string('cliinstallheader', 'install', $CFG->target_release)."\n";
293
294//Fist select language
295if ($interactive) {
296    cli_separator();
297    // Do not put the langs into columns because it is not compatible with RTL.
298    $default = $CFG->lang;
299    cli_heading(get_string('chooselanguagehead', 'install'));
300    if (array_key_exists($default, $languages)) {
301        echo $default.' - '.$languages[$default]."\n";
302    }
303    if ($default !== 'en') {
304        echo 'en - English (en)'."\n";
305    }
306    echo '? - '.get_string('availablelangs', 'install')."\n";
307    $prompt = get_string('clitypevaluedefault', 'admin', $CFG->lang);
308    $error = '';
309    do {
310        echo $error;
311        $input = cli_input($prompt, $default);
312
313        if ($input === '?') {
314            echo implode("\n", $languages)."\n";
315            $error = "\n";
316
317        } else {
318            $input = clean_param($input, PARAM_SAFEDIR);
319
320            if (!array_key_exists($input, $languages)) {
321                $error = get_string('cliincorrectvalueretry', 'admin')."\n";
322            } else {
323                $error = '';
324            }
325        }
326    } while ($error !== '');
327    $CFG->lang = $input;
328} else {
329    // already selected and verified
330}
331
332// Set directorypermissions first
333$chmod = octdec(clean_param($options['chmod'], PARAM_INT));
334if ($interactive) {
335    cli_separator();
336    cli_heading(get_string('datarootpermission', 'install'));
337    $prompt = get_string('clitypevaluedefault', 'admin', decoct($chmod));
338    $error = '';
339    do {
340        echo $error;
341        $input = cli_input($prompt, decoct($chmod));
342        $input = octdec(clean_param($input, PARAM_INT));
343        if (empty($input)) {
344            $error = get_string('cliincorrectvalueretry', 'admin')."\n";
345        } else {
346            $error = '';
347        }
348    } while ($error !== '');
349    $chmod = $input;
350
351} else {
352    if (empty($chmod)) {
353        $a = (object)array('option' => 'chmod', 'value' => decoct($chmod));
354        cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
355    }
356}
357$CFG->directorypermissions = $chmod;
358$CFG->filepermissions      = ($CFG->directorypermissions & 0666);
359$CFG->umaskpermissions     = (($CFG->directorypermissions & 0777) ^ 0777);
360
361//We need wwwroot before we test dataroot
362$wwwroot = clean_param($options['wwwroot'], PARAM_URL);
363$wwwroot = trim($wwwroot, '/');
364if ($interactive) {
365    cli_separator();
366    cli_heading(get_string('wwwroot', 'install'));
367    if (strpos($wwwroot, 'http') === 0) {
368        $prompt = get_string('clitypevaluedefault', 'admin', $wwwroot);
369    } else {
370        $wwwroot = null;
371        $prompt = get_string('clitypevalue', 'admin');
372    }
373    $error = '';
374    do {
375        echo $error;
376        $input = cli_input($prompt, $wwwroot);
377        $input = clean_param($input, PARAM_URL);
378        $input = trim($input, '/');
379        if (strpos($input, 'http') !== 0) {
380            $error = get_string('cliincorrectvalueretry', 'admin')."\n";
381        } else {
382            $error = '';
383        }
384    } while ($error !== '');
385    $wwwroot = $input;
386
387} else {
388    if (strpos($wwwroot, 'http') !== 0) {
389        $a = (object)array('option'=>'wwwroot', 'value'=>$wwwroot);
390        cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
391    }
392}
393$CFG->wwwroot       = $wwwroot;
394$CFG->httpswwwroot  = $CFG->wwwroot;
395
396//We need dataroot before lang download
397$CFG->dataroot = $options['dataroot'];
398if ($interactive) {
399    cli_separator();
400    $i=0;
401    while(is_dataroot_insecure()) {
402        $parrent = dirname($CFG->dataroot);
403        $i++;
404        if ($parrent == '/' or $parrent == '.' or preg_match('/^[a-z]:\\\?$/i', $parrent) or ($i > 100)) {
405            $CFG->dataroot = ''; //can not find secure location for dataroot
406            break;
407        }
408        $CFG->dataroot = dirname($parrent).'/moodledata';
409    }
410    cli_heading(get_string('dataroot', 'install'));
411    $error = '';
412    do {
413        if ($CFG->dataroot !== '') {
414            $prompt = get_string('clitypevaluedefault', 'admin', $CFG->dataroot);
415        } else {
416            $prompt = get_string('clitypevalue', 'admin');
417        }
418        echo $error;
419        $CFG->dataroot = cli_input($prompt, $CFG->dataroot);
420        if ($CFG->dataroot === '') {
421            $error = get_string('cliincorrectvalueretry', 'admin')."\n";
422        } else if (is_dataroot_insecure()) {
423            $CFG->dataroot = '';
424            $error = get_string('pathsunsecuredataroot', 'install')."\n";
425        } else {
426            if (install_init_dataroot($CFG->dataroot, $CFG->directorypermissions)) {
427                $error = '';
428            } else {
429                $a = (object)array('dataroot' => $CFG->dataroot);
430                $error = get_string('pathserrcreatedataroot', 'install', $a)."\n";
431            }
432        }
433
434    } while ($error !== '');
435
436} else {
437    if (is_dataroot_insecure()) {
438        cli_error(get_string('pathsunsecuredataroot', 'install'));
439    }
440    if (!install_init_dataroot($CFG->dataroot, $CFG->directorypermissions)) {
441        $a = (object)array('dataroot' => $CFG->dataroot);
442        cli_error(get_string('pathserrcreatedataroot', 'install', $a));
443    }
444}
445$CFG->tempdir       = $CFG->dataroot.'/temp';
446$CFG->backuptempdir = $CFG->tempdir.'/backup';
447$CFG->cachedir      = $CFG->dataroot.'/cache';
448$CFG->localcachedir = $CFG->dataroot.'/localcache';
449
450// download required lang packs
451if ($CFG->lang !== 'en') {
452    $installer = new lang_installer($CFG->lang);
453    $results = $installer->run();
454    foreach ($results as $langcode => $langstatus) {
455        if ($langstatus === lang_installer::RESULT_DOWNLOADERROR) {
456            $a       = new stdClass();
457            $a->url  = $installer->lang_pack_url($langcode);
458            $a->dest = $CFG->dataroot.'/lang';
459            cli_problem(get_string('remotedownloaderror', 'error', $a));
460        }
461    }
462}
463
464// switch the string_manager instance to stop using install/lang/
465$CFG->early_install_lang = false;
466$CFG->langotherroot      = $CFG->dataroot.'/lang';
467$CFG->langlocalroot      = $CFG->dataroot.'/lang';
468get_string_manager(true);
469
470// make sure we are installing stable release or require a confirmation
471if (isset($maturity)) {
472    if (($maturity < MATURITY_STABLE) and !$options['allow-unstable']) {
473        $maturitylevel = get_string('maturity'.$maturity, 'admin');
474
475        if ($interactive) {
476            cli_separator();
477            cli_heading(get_string('notice'));
478            echo get_string('maturitycorewarning', 'admin', $maturitylevel) . PHP_EOL;
479            echo get_string('morehelp') . ': ' . get_docs_url('admin/versions') . PHP_EOL;
480            echo get_string('continue') . PHP_EOL;
481            $prompt = get_string('cliyesnoprompt', 'admin');
482            $input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
483            if ($input == get_string('clianswerno', 'admin')) {
484                exit(1);
485            }
486        } else {
487            cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
488            cli_error(get_string('maturityallowunstable', 'admin'));
489        }
490    }
491}
492
493// ask for db type - show only drivers available
494if ($interactive) {
495    $options['dbtype'] = strtolower($options['dbtype']);
496    cli_separator();
497    cli_heading(get_string('databasetypehead', 'install'));
498    foreach ($databases as $type=>$database) {
499        echo " $type \n";
500    }
501    if (!empty($databases[$options['dbtype']])) {
502        $prompt = get_string('clitypevaluedefault', 'admin', $options['dbtype']);
503    } else {
504        $prompt = get_string('clitypevalue', 'admin');
505    }
506    $CFG->dbtype = cli_input($prompt, $options['dbtype'], array_keys($databases));
507
508} else {
509    if (empty($databases[$options['dbtype']])) {
510        $a = (object)array('option'=>'dbtype', 'value'=>$options['dbtype']);
511        cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
512    }
513    $CFG->dbtype = $options['dbtype'];
514}
515$database = $databases[$CFG->dbtype];
516
517
518// We cannot do any validation until all DB connection data is provided.
519$hintdatabase = '';
520do {
521    echo $hintdatabase;
522
523    // Ask for db host.
524    if ($interactive) {
525        cli_separator();
526        cli_heading(get_string('databasehost', 'install'));
527        if ($options['dbhost'] !== '') {
528            $prompt = get_string('clitypevaluedefault', 'admin', $options['dbhost']);
529        } else {
530            $prompt = get_string('clitypevalue', 'admin');
531        }
532        $CFG->dbhost = cli_input($prompt, $options['dbhost']);
533
534    } else {
535        $CFG->dbhost = $options['dbhost'];
536    }
537
538    // Ask for db name.
539    if ($interactive) {
540        cli_separator();
541        cli_heading(get_string('databasename', 'install'));
542        if ($options['dbname'] !== '') {
543            $prompt = get_string('clitypevaluedefault', 'admin', $options['dbname']);
544        } else {
545            $prompt = get_string('clitypevalue', 'admin');
546        }
547        $CFG->dbname = cli_input($prompt, $options['dbname']);
548
549    } else {
550        $CFG->dbname = $options['dbname'];
551    }
552
553    // Ask for db prefix.
554    if ($interactive) {
555        cli_separator();
556        cli_heading(get_string('dbprefix', 'install'));
557        //TODO: solve somehow the prefix trouble for oci.
558        if ($options['prefix'] !== '') {
559            $prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
560        } else {
561            $prompt = get_string('clitypevalue', 'admin');
562        }
563        $CFG->prefix = cli_input($prompt, $options['prefix']);
564
565    } else {
566        $CFG->prefix = $options['prefix'];
567    }
568
569    // Ask for db port.
570    if ($interactive) {
571        cli_separator();
572        cli_heading(get_string('databaseport', 'install'));
573        $prompt = get_string('clitypevaluedefault', 'admin', $options['dbport']);
574        $CFG->dboptions['dbport'] = (int) cli_input($prompt, $options['dbport']);
575
576    } else {
577        $CFG->dboptions['dbport'] = (int) $options['dbport'];
578    }
579    if ($CFG->dboptions['dbport'] <= 0) {
580        $CFG->dboptions['dbport'] = '';
581    }
582
583    // Ask for db socket.
584    if ($CFG->ostype === 'WINDOWS') {
585        $CFG->dboptions['dbsocket'] = '';
586
587    } else if ($interactive and empty($CFG->dboptions['dbport'])) {
588        cli_separator();
589        cli_heading(get_string('databasesocket', 'install'));
590        $prompt = get_string('clitypevaluedefault', 'admin', $options['dbsocket']);
591        $CFG->dboptions['dbsocket'] = cli_input($prompt, $options['dbsocket']);
592
593    } else {
594        $CFG->dboptions['dbsocket'] = $options['dbsocket'];
595    }
596
597    // Ask for db user.
598    if ($interactive) {
599        cli_separator();
600        cli_heading(get_string('databaseuser', 'install'));
601        if ($options['dbuser'] !== '') {
602            $prompt = get_string('clitypevaluedefault', 'admin', $options['dbuser']);
603        } else {
604            $prompt = get_string('clitypevalue', 'admin');
605        }
606        $CFG->dbuser = cli_input($prompt, $options['dbuser']);
607
608    } else {
609        $CFG->dbuser = $options['dbuser'];
610    }
611
612    // Ask for db password.
613    if ($interactive) {
614        cli_separator();
615        cli_heading(get_string('databasepass', 'install'));
616
617        if ($options['dbpass'] !== '') {
618            $prompt = get_string('clitypevaluedefault', 'admin', $options['dbpass']);
619        } else {
620            $prompt = get_string('clitypevalue', 'admin');
621        }
622
623        $CFG->dbpass = cli_input($prompt, $options['dbpass']);
624        if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation.
625            $distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
626                    array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']),
627                    $distro);
628        }
629        $hintdatabase = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
630                array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']));
631
632    } else {
633        $CFG->dbpass = $options['dbpass'];
634        $hintdatabase = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
635                array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']));
636        if ($hintdatabase !== '') {
637            cli_error(get_string('dbconnectionerror', 'install'));
638        }
639    }
640} while ($hintdatabase !== '');
641
642// If --skip-database option is provided, we do not need to ask for site fullname, shortname, adminuser, adminpass, adminemail.
643// These fields will be requested during the database install part.
644if (!$skipdatabase) {
645    // Ask for fullname.
646    if ($interactive) {
647        cli_separator();
648        cli_heading(get_string('fullsitename', 'moodle'));
649
650        if ($options['fullname'] !== '') {
651            $prompt = get_string('clitypevaluedefault', 'admin', $options['fullname']);
652        } else {
653            $prompt = get_string('clitypevalue', 'admin');
654        }
655
656        do {
657            $options['fullname'] = cli_input($prompt, $options['fullname']);
658        } while (empty($options['fullname']));
659    } else {
660        if (empty($options['fullname'])) {
661            $a = (object)['option' => 'fullname', 'value' => $options['fullname']];
662            cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
663        }
664    }
665
666    // Ask for shortname.
667    if ($interactive) {
668        cli_separator();
669        cli_heading(get_string('shortsitename', 'moodle'));
670
671        if ($options['shortname'] !== '') {
672            $prompt = get_string('clitypevaluedefault', 'admin', $options['shortname']);
673        } else {
674            $prompt = get_string('clitypevalue', 'admin');
675        }
676
677        do {
678            $options['shortname'] = cli_input($prompt, $options['shortname']);
679        } while (empty($options['shortname']));
680    } else {
681        if (empty($options['shortname'])) {
682            $a = (object)['option' => 'shortname', 'value' => $options['shortname']];
683            cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
684        }
685    }
686
687    // Ask for admin user name.
688    if ($interactive) {
689        cli_separator();
690        cli_heading(get_string('cliadminusername', 'install'));
691        if (!empty($options['adminuser'])) {
692            $prompt = get_string('clitypevaluedefault', 'admin', $options['adminuser']);
693        } else {
694            $prompt = get_string('clitypevalue', 'admin');
695        }
696        do {
697            $options['adminuser'] = cli_input($prompt, $options['adminuser']);
698        } while (empty($options['adminuser']) or $options['adminuser'] === 'guest');
699    } else {
700        if ((empty($options['adminuser']) || $options['adminuser'] === 'guest')) {
701            $a = (object)['option' => 'adminuser', 'value' => $options['adminuser']];
702            cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
703        }
704    }
705
706    // Ask for admin user password.
707    if ($interactive) {
708        cli_separator();
709        cli_heading(get_string('cliadminpassword', 'install'));
710        $prompt = get_string('clitypevalue', 'admin');
711        do {
712            $options['adminpass'] = cli_input($prompt);
713        } while (empty($options['adminpass']) or $options['adminpass'] === 'admin');
714    } else {
715        if ((empty($options['adminpass']) or $options['adminpass'] === 'admin')) {
716            $a = (object)['option' => 'adminpass', 'value' => $options['adminpass']];
717            cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
718        }
719    }
720
721    // Ask for the admin email address.
722    if ($interactive) {
723        cli_separator();
724        cli_heading(get_string('cliadminemail', 'install'));
725        $prompt = get_string('clitypevaluedefault', 'admin', $options['adminemail']);
726        $options['adminemail'] = cli_input($prompt, $options['adminemail']);
727    }
728
729    // Validate that the address provided was an e-mail address.
730    if (!empty($options['adminemail']) && !validate_email($options['adminemail'])) {
731        $a = (object)['option' => 'adminemail', 'value' => $options['adminemail']];
732        cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
733    }
734}
735
736// Ask for the upgrade key.
737if ($interactive) {
738    cli_separator();
739    cli_heading(get_string('upgradekeyset', 'admin'));
740    if ($options['upgradekey'] !== '') {
741        $prompt = get_string('clitypevaluedefault', 'admin', $options['upgradekey']);
742        $options['upgradekey'] = cli_input($prompt, $options['upgradekey']);
743    } else {
744        $prompt = get_string('clitypevalue', 'admin');
745        $options['upgradekey'] = cli_input($prompt);
746    }
747}
748
749// Set the upgrade key if it was provided.
750if ($options['upgradekey'] !== '') {
751    $CFG->upgradekey = $options['upgradekey'];
752}
753
754// The user does not also need to pass agree-license when --skip-database is provided as the user will need to accept
755// the license again in the database install part.
756if (!$skipdatabase) {
757    if ($interactive) {
758        if (!$options['agree-license']) {
759            cli_separator();
760            cli_heading(get_string('copyrightnotice'));
761            echo "Moodle  - Modular Object-Oriented Dynamic Learning Environment\n";
762            echo get_string('gpl3')."\n\n";
763            echo get_string('doyouagree')."\n";
764            $prompt = get_string('cliyesnoprompt', 'admin');
765            $input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
766            if ($input == get_string('clianswerno', 'admin')) {
767                exit(1);
768            }
769        }
770    } else {
771        if (!$options['agree-license'] && !$skipdatabase) {
772            cli_error(get_string('climustagreelicense', 'install'));
773        }
774    }
775}
776
777// Finally we have all info needed for config.php
778$configphp = install_generate_configphp($database, $CFG);
779umask(0137);
780if (($fh = fopen($configfile, 'w')) !== false) {
781    fwrite($fh, $configphp);
782    fclose($fh);
783}
784
785if (!file_exists($configfile)) {
786    cli_error('Can not create config file.');
787}
788
789// remember selected language
790$installlang = $CFG->lang;
791// return back to original dir before executing setup.php which changes the dir again
792chdir($olddir);
793// We have config.php, it is a real php script from now on :-)
794require($configfile);
795
796// use selected language
797$CFG->lang = $installlang;
798$SESSION->lang = $CFG->lang;
799
800require("$CFG->dirroot/version.php");
801
802// Test environment first.
803require_once($CFG->libdir . '/environmentlib.php');
804list($envstatus, $environment_results) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE);
805if (!$envstatus) {
806    $errors = environment_get_errors($environment_results);
807    cli_heading(get_string('environment', 'admin'));
808    foreach ($errors as $error) {
809        list($info, $report) = $error;
810        echo "!! $info !!\n$report\n\n";
811    }
812    exit(1);
813}
814
815// Test plugin dependencies.
816$failed = array();
817if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
818    cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
819    cli_error(get_string('pluginschecktodo', 'admin'));
820}
821
822if (!$skipdatabase) {
823    install_cli_database($options, $interactive);
824    // This needs to happen at the end to ensure it occurs after all caches
825    // have been purged for the last time.
826    // This will build a cached version of the current theme for the user
827    // to immediately start browsing the site.
828    require_once($CFG->libdir.'/upgradelib.php');
829    upgrade_themes();
830} else {
831    echo get_string('cliskipdatabase', 'install')."\n";
832}
833
834echo get_string('cliinstallfinished', 'install')."\n";
835exit(0); // 0 means success
836