3 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
19 * This script creates config.php file and prepares database.
21 * This script is not intended for beginners!
23 * - su to apache account or sudo before execution
24 * - not compatible with Windows platform
28 * @copyright 2009 Petr Skoda (http://skodak.org)
29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32 define('CLI_SCRIPT', true);
34 // extra execution prevention - we can not just require config.php here
35 if (isset($_SERVER['REMOTE_ADDR'])) {
40 "Command line Moodle installer, creates config.php and initializes database.
41 Please note you must execute this script with the same uid as apache
42 or use chmod/chown after installation.
44 Site defaults may be changed via local/defaults.php.
47 --chmod=OCTAL-MODE Permissions of new directories created within dataroot.
48 Default is 2777. You may want to change it to 2770
49 or 2750 or 750. See chmod man page for details.
50 --lang=CODE Installation and default site language.
51 --wwwroot=URL Web address for the Moodle site,
52 required in non-interactive mode.
53 --dataroot=DIR Location of the moodle data folder,
54 must not be web accessible. Default is moodledata
55 in the parent directory.
56 --dbtype=TYPE Database type. Default is mysqli
57 --dbhost=HOST Database host. Default is localhost
58 --dbname=NAME Database name. Default is moodle
59 --dbuser=USERNAME Database user. Default is root
60 --dbpass=PASSWORD Database password. Default is blank
61 --dbsocket Use database sockets. Available for some databases only.
62 --prefix=STRING Table prefix for above database tables. Default is mdl_
63 --fullname=STRING The fullname of the site
64 --shortname=STRING The shortname of the site
65 --adminuser=USERNAME Username for the moodle admin account. Default is admin
66 --adminpass=PASSWORD Password for the moodle admin account,
67 required in non-interactive mode.
68 --non-interactive No interactive questions, installation fails if any
70 --agree-license Indicates agreement with software license,
71 required in non-interactive mode.
72 --allow-unstable Install even if the version is not marked as stable yet,
73 required in non-interactive mode.
74 -h, --help Print out this help
77 \$sudo -u www-data /usr/bin/php admin/cli/install.php --lang=cs
78 "; //TODO: localize, mark as needed in install - to be translated later when everything is finished
81 // distro specific customisation
82 $distrolibfile = dirname(dirname(dirname(__FILE__))).'/install/distrolib.php';
84 if (file_exists($distrolibfile)) {
85 require_once($distrolibfile);
86 if (function_exists('distro_get_config')) {
87 $distro = distro_get_config();
91 // Nothing to do if config.php exists
92 $configfile = dirname(dirname(dirname(__FILE__))).'/config.php';
93 if (file_exists($configfile)) {
95 require_once($CFG->libdir.'/clilib.php');
96 list($options, $unrecognized) = cli_get_params(array('help'=>false), array('h'=>'help'));
98 if ($options['help']) {
103 if ($DB->get_manager()->table_exists('config')) {
104 cli_error(get_string('clialreadyinstalled', 'install'));
106 cli_error(get_string('clialreadyconfigured', 'install'));
112 // change directory so that includes below work properly
113 chdir(dirname($_SERVER['argv'][0]));
115 // Servers should define a default timezone in php.ini, but if they don't then make sure something is defined.
116 // This is a quick hack. Ideally we should ask the admin for a value. See MDL-22625 for more on this.
117 if (function_exists('date_default_timezone_set') and function_exists('date_default_timezone_get')) {
118 @date_default_timezone_set(@date_default_timezone_get());
121 // make sure PHP errors are displayed - helps with diagnosing of problems
122 @error_reporting(E_ALL);
123 @ini_set('display_errors', '1');
124 // we need a lot of memory
125 @ini_set('memory_limit', '128M');
127 /** Used by library scripts to check they are being called by Moodle */
128 define('MOODLE_INTERNAL', true);
130 // Check that PHP is of a sufficient version
131 if (version_compare(phpversion(), "5.3.2") < 0) {
132 $phpversion = phpversion();
133 // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
134 fwrite(STDERR, "Moodle 2.1 or later requires at least PHP 5.3.2 (currently using version $phpversion).\n");
135 fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
139 // set up configuration
140 $CFG = new stdClass();
142 $CFG->dirroot = dirname(dirname(dirname(__FILE__)));
143 $CFG->libdir = "$CFG->dirroot/lib";
144 $CFG->wwwroot = "http://localhost";
145 $CFG->httpswwwroot = $CFG->wwwroot;
146 $CFG->docroot = 'http://docs.moodle.org';
147 $CFG->running_installer = true;
148 $CFG->early_install_lang = true;
150 $parts = explode('/', str_replace('\\', '/', dirname(dirname(__FILE__))));
151 $CFG->admin = array_pop($parts);
153 //point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else
154 //the problem is that we need specific version of quickforms and hacked excel files :-(
155 ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path'));
157 require_once($CFG->libdir.'/installlib.php');
158 require_once($CFG->libdir.'/clilib.php');
159 require_once($CFG->libdir.'/setuplib.php');
160 require_once($CFG->libdir.'/textlib.class.php');
161 require_once($CFG->libdir.'/weblib.php');
162 require_once($CFG->libdir.'/dmllib.php');
163 require_once($CFG->libdir.'/moodlelib.php');
164 require_once($CFG->libdir.'/deprecatedlib.php');
165 require_once($CFG->libdir.'/adminlib.php');
166 require_once($CFG->libdir.'/componentlib.class.php');
168 require($CFG->dirroot.'/version.php');
169 $CFG->target_release = $release;
172 $databases = array('mysqli' => moodle_database::get_driver_instance('mysqli', 'native'),
173 'pgsql' => moodle_database::get_driver_instance('pgsql', 'native'),
174 'oci' => moodle_database::get_driver_instance('oci', 'native'),
175 'sqlsrv' => moodle_database::get_driver_instance('sqlsrv', 'native'), // MS SQL*Server PHP driver
176 'mssql' => moodle_database::get_driver_instance('mssql', 'native'), // FreeTDS driver
178 foreach ($databases as $type=>$database) {
179 if ($database->driver_installed() !== true) {
180 unset($databases[$type]);
183 if (empty($databases)) {
187 $defaultdb = key($databases);
190 // now get cli options
191 list($options, $unrecognized) = cli_get_params(
193 'chmod' => isset($distro->directorypermissions) ? sprintf('%04o',$distro->directorypermissions) : '2777', // let distros set dir permissions
194 'lang' => $CFG->lang,
196 'dataroot' => empty($distro->dataroot) ? str_replace('\\', '/', dirname(dirname(dirname(dirname(__FILE__)))).'/moodledata'): $distro->dataroot, // initialised later after including libs or by distro
197 'dbtype' => empty($distro->dbtype) ? $defaultdb : $distro->dbtype, // let distro skip dbtype selection
198 'dbhost' => empty($distro->dbhost) ? 'localhost' : $distro->dbhost, // let distros set dbhost
199 'dbname' => 'moodle',
200 'dbuser' => empty($distro->dbuser) ? 'root' : $distro->dbuser, // let distros set dbuser
206 'adminuser' => 'admin',
208 'non-interactive' => false,
209 'agree-license' => false,
210 'allow-unstable' => false,
218 $interactive = empty($options['non-interactive']);
221 $lang = clean_param($options['lang'], PARAM_SAFEDIR);
222 if (file_exists($CFG->dirroot.'/install/lang/'.$lang)) {
227 $unrecognized = implode("\n ", $unrecognized);
228 cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
231 if ($options['help']) {
237 echo get_string('cliinstallheader', 'install', $CFG->target_release)."\n";
239 //Fist select language
242 $languages = get_string_manager()->get_list_of_translations();
243 // Do not put the langs into columns because it is not compatible with RTL.
244 $langlist = implode("\n", $languages);
245 $default = $CFG->lang;
246 cli_heading(get_string('availablelangs', 'install'));
248 $prompt = get_string('clitypevaluedefault', 'admin', $CFG->lang);
252 $input = cli_input($prompt, $default);
253 $input = clean_param($input, PARAM_SAFEDIR);
255 if (!file_exists($CFG->dirroot.'/install/lang/'.$input)) {
256 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
260 } while ($error !== '');
263 // already selected and verified
266 // Set directorypermissions first
267 $chmod = octdec(clean_param($options['chmod'], PARAM_INT));
270 cli_heading(get_string('datarootpermission', 'install'));
271 $prompt = get_string('clitypevaluedefault', 'admin', decoct($chmod));
275 $input = cli_input($prompt, decoct($chmod));
276 $input = octdec(clean_param($input, PARAM_INT));
278 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
282 } while ($error !== '');
287 $a = (object)array('option' => 'chmod', 'value' => decoct($chmod));
288 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
291 $CFG->directorypermissions = $chmod;
293 //We need wwwroot before we test dataroot
294 $wwwroot = clean_param($options['wwwroot'], PARAM_URL);
295 $wwwroot = trim($wwwroot, '/');
298 cli_heading(get_string('wwwroot', 'install'));
299 if (strpos($wwwroot, 'http') === 0) {
300 $prompt = get_string('clitypevaluedefault', 'admin', $wwwroot);
303 $prompt = get_string('clitypevalue', 'admin');
308 $input = cli_input($prompt, $wwwroot);
309 $input = clean_param($input, PARAM_URL);
310 $input = trim($input, '/');
311 if (strpos($input, 'http') !== 0) {
312 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
316 } while ($error !== '');
320 if (strpos($wwwroot, 'http') !== 0) {
321 $a = (object)array('option'=>'wwwroot', 'value'=>$wwwroot);
322 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
325 $CFG->wwwroot = $wwwroot;
326 $CFG->httpswwwroot = $CFG->wwwroot;
329 //We need dataroot before lang download
330 $CFG->dataroot = $options['dataroot'];
334 while(is_dataroot_insecure()) {
335 $parrent = dirname($CFG->dataroot);
337 if ($parrent == '/' or $parrent == '.' or preg_match('/^[a-z]:\\\?$/i', $parrent) or ($i > 100)) {
338 $CFG->dataroot = ''; //can not find secure location for dataroot
341 $CFG->dataroot = dirname($parrent).'/moodledata';
343 cli_heading(get_string('dataroot', 'install'));
346 if ($CFG->dataroot !== '') {
347 $prompt = get_string('clitypevaluedefault', 'admin', $CFG->dataroot);
349 $prompt = get_string('clitypevalue', 'admin');
352 $CFG->dataroot = cli_input($prompt, $CFG->dataroot);
353 if ($CFG->dataroot === '') {
354 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
355 } else if (is_dataroot_insecure()) {
357 $error = get_string('pathsunsecuredataroot', 'install')."\n";
359 if (install_init_dataroot($CFG->dataroot, $CFG->directorypermissions)) {
362 $a = (object)array('dataroot' => $CFG->dataroot);
363 $error = get_string('pathserrcreatedataroot', 'install', $a)."\n";
367 } while ($error !== '');
370 if (is_dataroot_insecure()) {
371 cli_error(get_string('pathsunsecuredataroot', 'install'));
373 if (!install_init_dataroot($CFG->dataroot, $CFG->directorypermissions)) {
374 $a = (object)array('dataroot' => $CFG->dataroot);
375 cli_error(get_string('pathserrcreatedataroot', 'install', $a));
378 $CFG->tempdir = $CFG->dataroot.'/temp';
379 $CFG->cachedir = $CFG->dataroot.'/cache';
381 // download required lang packs
382 if ($CFG->lang !== 'en') {
383 $installer = new lang_installer($CFG->lang);
384 $results = $installer->run();
385 foreach ($results as $langcode => $langstatus) {
386 if ($langstatus === lang_installer::RESULT_DOWNLOADERROR) {
388 $a->url = $installer->lang_pack_url($langcode);
389 $a->dest = $CFG->dataroot.'/lang';
390 cli_problem(get_string('remotedownloaderror', 'error', $a));
395 // switch the string_manager instance to stop using install/lang/
396 $CFG->early_install_lang = false;
397 $CFG->langotherroot = $CFG->dataroot.'/lang';
398 $CFG->langlocalroot = $CFG->dataroot.'/lang';
399 get_string_manager(true);
401 // make sure we are installing stable release or require a confirmation
402 if (isset($maturity)) {
403 if (($maturity < MATURITY_STABLE) and !$options['allow-unstable']) {
404 $maturitylevel = get_string('maturity'.$maturity, 'admin');
408 cli_heading(get_string('notice'));
409 echo get_string('maturitycorewarning', 'admin', $maturitylevel) . PHP_EOL;
410 echo get_string('morehelp') . ': ' . get_docs_url('admin/versions') . PHP_EOL;
411 echo get_string('continue') . PHP_EOL;
412 $prompt = get_string('cliyesnoprompt', 'admin');
413 $input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
414 if ($input == get_string('clianswerno', 'admin')) {
418 cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
419 cli_error(get_string('maturityallowunstable', 'admin'));
424 // ask for db type - show only drivers available
426 $options['dbtype'] = strtolower($options['dbtype']);
428 cli_heading(get_string('databasetypehead', 'install'));
429 foreach ($databases as $type=>$database) {
432 if (!empty($databases[$options['dbtype']])) {
433 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbtype']);
435 $prompt = get_string('clitypevalue', 'admin');
437 $CFG->dbtype = cli_input($prompt, $options['dbtype'], array_keys($databases));
440 if (empty($databases[$options['dbtype']])) {
441 $a = (object)array('option'=>'dbtype', 'value'=>$options['dbtype']);
442 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
444 $CFG->dbtype = $options['dbtype'];
446 $database = $databases[$CFG->dbtype];
452 cli_heading(get_string('databasehost', 'install'));
453 if ($options['dbhost'] !== '') {
454 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbhost']);
456 $prompt = get_string('clitypevalue', 'admin');
458 $CFG->dbhost = cli_input($prompt, $options['dbhost']);
461 $CFG->dbhost = $options['dbhost'];
467 cli_heading(get_string('databasename', 'install'));
468 if ($options['dbname'] !== '') {
469 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbname']);
471 $prompt = get_string('clitypevalue', 'admin');
473 $CFG->dbname = cli_input($prompt, $options['dbname']);
476 $CFG->dbname = $options['dbname'];
482 cli_heading(get_string('dbprefix', 'install'));
483 //TODO: solve somehow the prefix trouble for oci
484 if ($options['prefix'] !== '') {
485 $prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
487 $prompt = get_string('clitypevalue', 'admin');
489 $CFG->prefix = cli_input($prompt, $options['prefix']);
492 $CFG->prefix = $options['prefix'];
498 cli_heading(get_string('databaseuser', 'install'));
499 if ($options['dbuser'] !== '') {
500 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbuser']);
502 $prompt = get_string('clitypevalue', 'admin');
504 $CFG->dbuser = cli_input($prompt, $options['dbuser']);
507 $CFG->dbuser = $options['dbuser'];
510 // ask for db password
513 cli_heading(get_string('databasepass', 'install'));
515 if ($options['dbpass'] !== '') {
516 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbpass']);
518 $prompt = get_string('clitypevalue', 'admin');
521 $CFG->dbpass = cli_input($prompt, $options['dbpass']);
522 if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation
523 $distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']), $distro);
525 $hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']));
526 } while ($hint_database !== '');
529 $CFG->dbpass = $options['dbpass'];
530 $hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']));
531 if ($hint_database !== '') {
532 cli_error(get_string('dbconnectionerror', 'install'));
539 cli_heading(get_string('fullsitename', 'moodle'));
541 if ($options['fullname'] !== '') {
542 $prompt = get_string('clitypevaluedefault', 'admin', $options['fullname']);
544 $prompt = get_string('clitypevalue', 'admin');
548 $options['fullname'] = cli_input($prompt, $options['fullname']);
549 } while (empty($options['fullname']));
551 if (empty($options['fullname'])) {
552 $a = (object)array('option'=>'fullname', 'value'=>$options['fullname']);
553 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
560 cli_heading(get_string('shortsitename', 'moodle'));
562 if ($options['shortname'] !== '') {
563 $prompt = get_string('clitypevaluedefault', 'admin', $options['shortname']);
565 $prompt = get_string('clitypevalue', 'admin');
569 $options['shortname'] = cli_input($prompt, $options['shortname']);
570 } while (empty($options['shortname']));
572 if (empty($options['shortname'])) {
573 $a = (object)array('option'=>'shortname', 'value'=>$options['shortname']);
574 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
578 // ask for admin user name
581 cli_heading(get_string('cliadminusername', 'install'));
582 if (!empty($options['adminuser'])) {
583 $prompt = get_string('clitypevaluedefault', 'admin', $options['adminuser']);
585 $prompt = get_string('clitypevalue', 'admin');
588 $options['adminuser'] = cli_input($prompt, $options['adminuser']);
589 } while (empty($options['adminuser']) or $options['adminuser'] === 'guest');
591 if (empty($options['adminuser']) or $options['adminuser'] === 'guest') {
592 $a = (object)array('option'=>'adminuser', 'value'=>$options['adminuser']);
593 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
597 // ask for admin user password
600 cli_heading(get_string('cliadminpassword', 'install'));
601 $prompt = get_string('clitypevalue', 'admin');
603 $options['adminpass'] = cli_input($prompt);
604 } while (empty($options['adminpass']) or $options['adminpass'] === 'admin');
606 if (empty($options['adminpass']) or $options['adminpass'] === 'admin') {
607 $a = (object)array('option'=>'adminpass', 'value'=>$options['adminpass']);
608 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
613 if (!$options['agree-license']) {
615 cli_heading(get_string('copyrightnotice'));
616 echo "Moodle - Modular Object-Oriented Dynamic Learning Environment\n";
617 echo get_string('gpl3')."\n\n";
618 echo get_string('doyouagree')."\n";
619 $prompt = get_string('cliyesnoprompt', 'admin');
620 $input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
621 if ($input == get_string('clianswerno', 'admin')) {
626 if (!$options['agree-license']) {
627 cli_error(get_string('climustagreelicense', 'install'));
631 // Finally we have all info needed for config.php
632 $configphp = install_generate_configphp($database, $CFG);
634 if (($fh = fopen($configfile, 'w')) !== false) {
635 fwrite($fh, $configphp);
639 if (!file_exists($configfile)) {
640 cli_error('Can not create config file.');
643 // remember selected language
644 $installlang = $CFG->lang;
645 // return back to original dir before executing setup.php which changes the dir again
647 // We have config.php, it is a real php script from now on :-)
648 require($configfile);
650 // use selected language
651 $CFG->lang = $installlang;
652 $SESSION->lang = $CFG->lang;
654 require("$CFG->dirroot/version.php");
656 // Test environment first.
657 require_once($CFG->libdir . '/environmentlib.php');
658 list($envstatus, $environment_results) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE);
660 $errors = environment_get_errors($environment_results);
661 cli_heading(get_string('environment', 'admin'));
662 foreach ($errors as $error) {
663 list($info, $report) = $error;
664 echo "!! $info !!\n$report\n\n";
669 // Test plugin dependencies.
670 require_once($CFG->libdir . '/pluginlib.php');
672 if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
673 cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
674 cli_error(get_string('pluginschecktodo', 'admin'));
677 install_cli_database($options, $interactive);
679 echo get_string('cliinstallfinished', 'install')."\n";
680 exit(0); // 0 means success