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 // Disables all caching.
131 define('CACHE_DISABLE_ALL', true);
133 // Check that PHP is of a sufficient version
134 if (version_compare(phpversion(), "5.3.3") < 0) {
135 $phpversion = phpversion();
136 // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
137 fwrite(STDERR
, "Moodle 2.5 or later requires at least PHP 5.3.3 (currently using version $phpversion).\n");
138 fwrite(STDERR
, "Please upgrade your server software or install older Moodle version.\n");
142 // set up configuration
143 $CFG = new stdClass();
145 $CFG->dirroot
= dirname(dirname(dirname(__FILE__
)));
146 $CFG->libdir
= "$CFG->dirroot/lib";
147 $CFG->wwwroot
= "http://localhost";
148 $CFG->httpswwwroot
= $CFG->wwwroot
;
149 $CFG->docroot
= 'http://docs.moodle.org';
150 $CFG->running_installer
= true;
151 $CFG->early_install_lang
= true;
152 $CFG->ostype
= (stristr(PHP_OS
, 'win') && !stristr(PHP_OS
, 'darwin')) ?
'WINDOWS' : 'UNIX';
154 $parts = explode('/', str_replace('\\', '/', dirname(dirname(__FILE__
))));
155 $CFG->admin
= array_pop($parts);
157 //point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else
158 //the problem is that we need specific version of quickforms and hacked excel files :-(
159 ini_set('include_path', $CFG->libdir
.'/pear' . PATH_SEPARATOR
. ini_get('include_path'));
161 require_once($CFG->libdir
.'/installlib.php');
162 require_once($CFG->libdir
.'/clilib.php');
163 require_once($CFG->libdir
.'/setuplib.php');
164 require_once($CFG->libdir
.'/textlib.class.php');
165 require_once($CFG->libdir
.'/weblib.php');
166 require_once($CFG->libdir
.'/dmllib.php');
167 require_once($CFG->libdir
.'/moodlelib.php');
168 require_once($CFG->libdir
.'/deprecatedlib.php');
169 require_once($CFG->libdir
.'/adminlib.php');
170 require_once($CFG->libdir
.'/componentlib.class.php');
171 require_once($CFG->dirroot
.'/cache/lib.php');
173 require($CFG->dirroot
.'/version.php');
174 $CFG->target_release
= $release;
177 $databases = array('mysqli' => moodle_database
::get_driver_instance('mysqli', 'native'),
178 'pgsql' => moodle_database
::get_driver_instance('pgsql', 'native'),
179 'oci' => moodle_database
::get_driver_instance('oci', 'native'),
180 'sqlsrv' => moodle_database
::get_driver_instance('sqlsrv', 'native'), // MS SQL*Server PHP driver
181 'mssql' => moodle_database
::get_driver_instance('mssql', 'native'), // FreeTDS driver
183 foreach ($databases as $type=>$database) {
184 if ($database->driver_installed() !== true) {
185 unset($databases[$type]);
188 if (empty($databases)) {
192 $defaultdb = key($databases);
195 // now get cli options
196 list($options, $unrecognized) = cli_get_params(
198 'chmod' => isset($distro->directorypermissions
) ?
sprintf('%04o',$distro->directorypermissions
) : '2777', // let distros set dir permissions
199 'lang' => $CFG->lang
,
201 'dataroot' => empty($distro->dataroot
) ?
str_replace('\\', '/', dirname(dirname(dirname(dirname(__FILE__
)))).'/moodledata'): $distro->dataroot
, // initialised later after including libs or by distro
202 'dbtype' => empty($distro->dbtype
) ?
$defaultdb : $distro->dbtype
, // let distro skip dbtype selection
203 'dbhost' => empty($distro->dbhost
) ?
'localhost' : $distro->dbhost
, // let distros set dbhost
204 'dbname' => 'moodle',
205 'dbuser' => empty($distro->dbuser
) ?
'root' : $distro->dbuser
, // let distros set dbuser
211 'adminuser' => 'admin',
213 'non-interactive' => false,
214 'agree-license' => false,
215 'allow-unstable' => false,
223 $interactive = empty($options['non-interactive']);
226 $lang = clean_param($options['lang'], PARAM_SAFEDIR
);
227 if (file_exists($CFG->dirroot
.'/install/lang/'.$lang)) {
232 $unrecognized = implode("\n ", $unrecognized);
233 cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
236 if ($options['help']) {
242 echo get_string('cliinstallheader', 'install', $CFG->target_release
)."\n";
244 //Fist select language
247 $languages = get_string_manager()->get_list_of_translations();
248 // Do not put the langs into columns because it is not compatible with RTL.
249 $langlist = implode("\n", $languages);
250 $default = $CFG->lang
;
251 cli_heading(get_string('availablelangs', 'install'));
253 $prompt = get_string('clitypevaluedefault', 'admin', $CFG->lang
);
257 $input = cli_input($prompt, $default);
258 $input = clean_param($input, PARAM_SAFEDIR
);
260 if (!file_exists($CFG->dirroot
.'/install/lang/'.$input)) {
261 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
265 } while ($error !== '');
268 // already selected and verified
271 // Set directorypermissions first
272 $chmod = octdec(clean_param($options['chmod'], PARAM_INT
));
275 cli_heading(get_string('datarootpermission', 'install'));
276 $prompt = get_string('clitypevaluedefault', 'admin', decoct($chmod));
280 $input = cli_input($prompt, decoct($chmod));
281 $input = octdec(clean_param($input, PARAM_INT
));
283 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
287 } while ($error !== '');
292 $a = (object)array('option' => 'chmod', 'value' => decoct($chmod));
293 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
296 $CFG->directorypermissions
= $chmod;
298 //We need wwwroot before we test dataroot
299 $wwwroot = clean_param($options['wwwroot'], PARAM_URL
);
300 $wwwroot = trim($wwwroot, '/');
303 cli_heading(get_string('wwwroot', 'install'));
304 if (strpos($wwwroot, 'http') === 0) {
305 $prompt = get_string('clitypevaluedefault', 'admin', $wwwroot);
308 $prompt = get_string('clitypevalue', 'admin');
313 $input = cli_input($prompt, $wwwroot);
314 $input = clean_param($input, PARAM_URL
);
315 $input = trim($input, '/');
316 if (strpos($input, 'http') !== 0) {
317 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
321 } while ($error !== '');
325 if (strpos($wwwroot, 'http') !== 0) {
326 $a = (object)array('option'=>'wwwroot', 'value'=>$wwwroot);
327 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
330 $CFG->wwwroot
= $wwwroot;
331 $CFG->httpswwwroot
= $CFG->wwwroot
;
334 //We need dataroot before lang download
335 $CFG->dataroot
= $options['dataroot'];
339 while(is_dataroot_insecure()) {
340 $parrent = dirname($CFG->dataroot
);
342 if ($parrent == '/' or $parrent == '.' or preg_match('/^[a-z]:\\\?$/i', $parrent) or ($i > 100)) {
343 $CFG->dataroot
= ''; //can not find secure location for dataroot
346 $CFG->dataroot
= dirname($parrent).'/moodledata';
348 cli_heading(get_string('dataroot', 'install'));
351 if ($CFG->dataroot
!== '') {
352 $prompt = get_string('clitypevaluedefault', 'admin', $CFG->dataroot
);
354 $prompt = get_string('clitypevalue', 'admin');
357 $CFG->dataroot
= cli_input($prompt, $CFG->dataroot
);
358 if ($CFG->dataroot
=== '') {
359 $error = get_string('cliincorrectvalueretry', 'admin')."\n";
360 } else if (is_dataroot_insecure()) {
362 $error = get_string('pathsunsecuredataroot', 'install')."\n";
364 if (install_init_dataroot($CFG->dataroot
, $CFG->directorypermissions
)) {
367 $a = (object)array('dataroot' => $CFG->dataroot
);
368 $error = get_string('pathserrcreatedataroot', 'install', $a)."\n";
372 } while ($error !== '');
375 if (is_dataroot_insecure()) {
376 cli_error(get_string('pathsunsecuredataroot', 'install'));
378 if (!install_init_dataroot($CFG->dataroot
, $CFG->directorypermissions
)) {
379 $a = (object)array('dataroot' => $CFG->dataroot
);
380 cli_error(get_string('pathserrcreatedataroot', 'install', $a));
383 $CFG->tempdir
= $CFG->dataroot
.'/temp';
384 $CFG->cachedir
= $CFG->dataroot
.'/cache';
386 // download required lang packs
387 if ($CFG->lang
!== 'en') {
388 $installer = new lang_installer($CFG->lang
);
389 $results = $installer->run();
390 foreach ($results as $langcode => $langstatus) {
391 if ($langstatus === lang_installer
::RESULT_DOWNLOADERROR
) {
393 $a->url
= $installer->lang_pack_url($langcode);
394 $a->dest
= $CFG->dataroot
.'/lang';
395 cli_problem(get_string('remotedownloaderror', 'error', $a));
400 // switch the string_manager instance to stop using install/lang/
401 $CFG->early_install_lang
= false;
402 $CFG->langotherroot
= $CFG->dataroot
.'/lang';
403 $CFG->langlocalroot
= $CFG->dataroot
.'/lang';
404 get_string_manager(true);
406 // make sure we are installing stable release or require a confirmation
407 if (isset($maturity)) {
408 if (($maturity < MATURITY_STABLE
) and !$options['allow-unstable']) {
409 $maturitylevel = get_string('maturity'.$maturity, 'admin');
413 cli_heading(get_string('notice'));
414 echo get_string('maturitycorewarning', 'admin', $maturitylevel) . PHP_EOL
;
415 echo get_string('morehelp') . ': ' . get_docs_url('admin/versions') . PHP_EOL
;
416 echo get_string('continue') . PHP_EOL
;
417 $prompt = get_string('cliyesnoprompt', 'admin');
418 $input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
419 if ($input == get_string('clianswerno', 'admin')) {
423 cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
424 cli_error(get_string('maturityallowunstable', 'admin'));
429 // ask for db type - show only drivers available
431 $options['dbtype'] = strtolower($options['dbtype']);
433 cli_heading(get_string('databasetypehead', 'install'));
434 foreach ($databases as $type=>$database) {
437 if (!empty($databases[$options['dbtype']])) {
438 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbtype']);
440 $prompt = get_string('clitypevalue', 'admin');
442 $CFG->dbtype
= cli_input($prompt, $options['dbtype'], array_keys($databases));
445 if (empty($databases[$options['dbtype']])) {
446 $a = (object)array('option'=>'dbtype', 'value'=>$options['dbtype']);
447 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
449 $CFG->dbtype
= $options['dbtype'];
451 $database = $databases[$CFG->dbtype
];
457 cli_heading(get_string('databasehost', 'install'));
458 if ($options['dbhost'] !== '') {
459 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbhost']);
461 $prompt = get_string('clitypevalue', 'admin');
463 $CFG->dbhost
= cli_input($prompt, $options['dbhost']);
466 $CFG->dbhost
= $options['dbhost'];
472 cli_heading(get_string('databasename', 'install'));
473 if ($options['dbname'] !== '') {
474 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbname']);
476 $prompt = get_string('clitypevalue', 'admin');
478 $CFG->dbname
= cli_input($prompt, $options['dbname']);
481 $CFG->dbname
= $options['dbname'];
487 cli_heading(get_string('dbprefix', 'install'));
488 //TODO: solve somehow the prefix trouble for oci
489 if ($options['prefix'] !== '') {
490 $prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
492 $prompt = get_string('clitypevalue', 'admin');
494 $CFG->prefix
= cli_input($prompt, $options['prefix']);
497 $CFG->prefix
= $options['prefix'];
503 cli_heading(get_string('databaseuser', 'install'));
504 if ($options['dbuser'] !== '') {
505 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbuser']);
507 $prompt = get_string('clitypevalue', 'admin');
509 $CFG->dbuser
= cli_input($prompt, $options['dbuser']);
512 $CFG->dbuser
= $options['dbuser'];
515 // ask for db password
518 cli_heading(get_string('databasepass', 'install'));
520 if ($options['dbpass'] !== '') {
521 $prompt = get_string('clitypevaluedefault', 'admin', $options['dbpass']);
523 $prompt = get_string('clitypevalue', 'admin');
526 $CFG->dbpass
= cli_input($prompt, $options['dbpass']);
527 if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation
528 $distro = distro_pre_create_db($database, $CFG->dbhost
, $CFG->dbuser
, $CFG->dbpass
, $CFG->dbname
, $CFG->prefix
, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']), $distro);
530 $hint_database = install_db_validate($database, $CFG->dbhost
, $CFG->dbuser
, $CFG->dbpass
, $CFG->dbname
, $CFG->prefix
, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']));
531 } while ($hint_database !== '');
534 $CFG->dbpass
= $options['dbpass'];
535 $hint_database = install_db_validate($database, $CFG->dbhost
, $CFG->dbuser
, $CFG->dbpass
, $CFG->dbname
, $CFG->prefix
, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']));
536 if ($hint_database !== '') {
537 cli_error(get_string('dbconnectionerror', 'install'));
544 cli_heading(get_string('fullsitename', 'moodle'));
546 if ($options['fullname'] !== '') {
547 $prompt = get_string('clitypevaluedefault', 'admin', $options['fullname']);
549 $prompt = get_string('clitypevalue', 'admin');
553 $options['fullname'] = cli_input($prompt, $options['fullname']);
554 } while (empty($options['fullname']));
556 if (empty($options['fullname'])) {
557 $a = (object)array('option'=>'fullname', 'value'=>$options['fullname']);
558 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
565 cli_heading(get_string('shortsitename', 'moodle'));
567 if ($options['shortname'] !== '') {
568 $prompt = get_string('clitypevaluedefault', 'admin', $options['shortname']);
570 $prompt = get_string('clitypevalue', 'admin');
574 $options['shortname'] = cli_input($prompt, $options['shortname']);
575 } while (empty($options['shortname']));
577 if (empty($options['shortname'])) {
578 $a = (object)array('option'=>'shortname', 'value'=>$options['shortname']);
579 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
583 // ask for admin user name
586 cli_heading(get_string('cliadminusername', 'install'));
587 if (!empty($options['adminuser'])) {
588 $prompt = get_string('clitypevaluedefault', 'admin', $options['adminuser']);
590 $prompt = get_string('clitypevalue', 'admin');
593 $options['adminuser'] = cli_input($prompt, $options['adminuser']);
594 } while (empty($options['adminuser']) or $options['adminuser'] === 'guest');
596 if (empty($options['adminuser']) or $options['adminuser'] === 'guest') {
597 $a = (object)array('option'=>'adminuser', 'value'=>$options['adminuser']);
598 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
602 // ask for admin user password
605 cli_heading(get_string('cliadminpassword', 'install'));
606 $prompt = get_string('clitypevalue', 'admin');
608 $options['adminpass'] = cli_input($prompt);
609 } while (empty($options['adminpass']) or $options['adminpass'] === 'admin');
611 if (empty($options['adminpass']) or $options['adminpass'] === 'admin') {
612 $a = (object)array('option'=>'adminpass', 'value'=>$options['adminpass']);
613 cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
618 if (!$options['agree-license']) {
620 cli_heading(get_string('copyrightnotice'));
621 echo "Moodle - Modular Object-Oriented Dynamic Learning Environment\n";
622 echo get_string('gpl3')."\n\n";
623 echo get_string('doyouagree')."\n";
624 $prompt = get_string('cliyesnoprompt', 'admin');
625 $input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
626 if ($input == get_string('clianswerno', 'admin')) {
631 if (!$options['agree-license']) {
632 cli_error(get_string('climustagreelicense', 'install'));
636 // Finally we have all info needed for config.php
637 $configphp = install_generate_configphp($database, $CFG);
639 if (($fh = fopen($configfile, 'w')) !== false) {
640 fwrite($fh, $configphp);
644 if (!file_exists($configfile)) {
645 cli_error('Can not create config file.');
648 // remember selected language
649 $installlang = $CFG->lang
;
650 // return back to original dir before executing setup.php which changes the dir again
652 // We have config.php, it is a real php script from now on :-)
653 require($configfile);
655 // use selected language
656 $CFG->lang
= $installlang;
657 $SESSION->lang
= $CFG->lang
;
659 require("$CFG->dirroot/version.php");
661 // Test environment first.
662 require_once($CFG->libdir
. '/environmentlib.php');
663 list($envstatus, $environment_results) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE
);
665 $errors = environment_get_errors($environment_results);
666 cli_heading(get_string('environment', 'admin'));
667 foreach ($errors as $error) {
668 list($info, $report) = $error;
669 echo "!! $info !!\n$report\n\n";
674 // Test plugin dependencies.
675 require_once($CFG->libdir
. '/pluginlib.php');
677 if (!plugin_manager
::instance()->all_plugins_ok($version, $failed)) {
678 cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
679 cli_error(get_string('pluginschecktodo', 'admin'));
682 install_cli_database($options, $interactive);
684 echo get_string('cliinstallfinished', 'install')."\n";
685 exit(0); // 0 means success