=== added file 'includes/install.mysql.inc' --- /dev/null +++ includes/install.mysql.inc @@ -0,0 +1,138 @@ +'. mysql_error() .'
'. $query .'" and MySQL reported the following error: "'. $error .'".', 'error');
+ $err = TRUE;
+ }
+ else {
+ $success[] = 'INSERT';
+ }
+
+ // Test UPDATE
+ $query = 'UPDATE drupal_install_test SET id = 2;';
+ $result = mysql_query("$query");
+ if ($error = mysql_error()) {
+ drupal_set_message('We were unable to update a value in a test table on your MySQL database server. We tried updating a value with the command "'. $query .'" and MySQL reported the following error: "'. $error .'".', 'error');
+ $err = TRUE;
+ }
+ else {
+ $success[] = 'UPDATE';
+ }
+
+ // Test LOCK
+ $query = 'LOCK TABLES drupal_install_test WRITE;';
+ $result = mysql_query("$query");
+ if ($error = mysql_error()) {
+ drupal_set_message('We were unable to lock a test table on your MySQL database server. We tried locking a table with the command "'. $query .'" and MySQL reported the following error: "'. $error .'".', 'error');
+ $err = TRUE;
+ }
+ else {
+ $success[] = 'LOCK';
+ }
+
+ // Test UNLOCK
+ $query = 'UNLOCK TABLES;';
+ $result = mysql_query("$query");
+ if ($error = mysql_error()) {
+ drupal_set_message('We were unable to unlock a test table on your MySQL database server. We tried unlocking a table with the command "'. $query .'" and MySQL reported the following error: "'. $error .'".', 'error');
+ $err = TRUE;
+ }
+ else {
+ $success[] = 'UNLOCK';
+ }
+
+ // Test DELETE
+ $query = 'DELETE FROM drupal_install_test;';
+ $result = mysql_query("$query");
+ if ($error = mysql_error()) {
+ drupal_set_message('We were unable to delete a value from a test table on your MySQL database server. We tried deleting a value with the command "'. $query .'" and MySQL reported the following error: "'. $error .'".', 'error');
+ $err = TRUE;
+ }
+ else {
+ $success[] = 'DELETE';
+ }
+
+ // Test DROP
+ $query = 'DROP TABLE drupal_install_test;';
+ $result = mysql_query("$query");
+ if ($error = mysql_error()) {
+ drupal_set_message('We were unable to drop a test table from your MySQL database server. We tried dropping a table with the command "'. $query .'" and MySQL reported the following error: "'. $error .'".', 'error');
+ $err = TRUE;
+ }
+ else {
+ $success[] = 'DROP';
+ }
+
+ if ($err) {
+ return FALSE;
+ }
+
+ mysql_close($connection);
+ return TRUE;
+ }
+ else {
+ drupal_set_message('Failure to connect to your MySQL database server. MySQL reports the following message: '. mysql_error() .'This either means that the username and password information in your settings.php file is incorrect or we can\'t contact the MySQL database server through the mysqli libraries. This could also mean your hosting provider\'s database server is down.
settings.php configuration file.',
+ );
+
+ $form['save'] = array(
+ '#type' => 'submit',
+ '#value' => 'Save configuration',
+ );
+ $form['errors'] = array();
+ $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file);
+ $form['_db_url'] = array('#type' => 'value');
+ $form['#action'] = "install.php?profile=$profile";
+ $form['#redirect'] = NULL;
+ drupal_maintenance_theme();
+ $output = drupal_get_form('drupal_install_settings', $form);
+ drupal_set_title('Database configuration');
+ print theme('install_page', st('Please fill out the following information to configure your %drupal site.
', array('%drupal' => _install_profile_name())). $output); + exit; +} + +function st($string, $args = array()) { + return strtr($string, array_map('check_plain', $args)); +} + +function _drupal_install_settings_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_path, $settings_file, $form = NULL) { + global $db_url; + if (!empty($db_prefix) && preg_match('/[^A-Za-z0-9_]/', $db_prefix)) { + form_set_error('db_prefix', st('The database prefix you have entered,%db_prefix, is invalid. The database prefix can only contain alphanumeric characters and underscores.', array('%db_prefix' => $db_prefix)), 'error');
+ }
+ if ($db_user == 'username' && $db_pass == 'password') {
+ form_set_error('db_user', st('You have configured %drupal to use the default username and password. This is not allowed for security reasons.', array('%drupal' => _install_profile_name())));
+ }
+ // Verify database settings
+ $db_type = substr($db_url, 0, strpos($db_url, '://'));
+ $databases = drupal_detect_database_types();
+ if (!in_array($db_type, $databases)) {
+ form_set_error('db_type', "In your $settings_file file you have configured Drupal to use a $db_type database server, however your PHP installation currently does not support this database type.");
+ }
+ else {
+ $db_url = $db_type .'://'. $db_user .($db_pass ? ':'. $db_pass : '') .'@'. ($db_host ? $db_host : 'localhost') .'/'. $db_path;
+ if (isset($form)) {
+ form_set_value($form['_db_url'], $db_url);
+ }
+ $success = array();
+ if (!drupal_test_mysql($db_url, $success)) {
+ form_set_error('db_type', 'In order for Drupal to work and to proceed with the installation process you must resolve all MySQL permission issues reported above. We were able to verify that we have permission for the following MySQL commands: '. implode($success, ', ') .'. For more help with configuring your MySQL database server, see the Installation and upgrading handbook. If you are unsure what any of this means you should probably contact your hosting provider.', 'error');
+ }
+ }
+ if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_WRITEABLE)) {
+ form_set_error('errors', 'The Drupal installer requires write permissions to settings.php during the installation process.');
+ }
+}
+
+function drupal_install_settings_validate($form_id, $form_values, $form) {
+ global $db_url;
+ _drupal_install_settings_validate($form_values['db_prefix'], $form_values['db_type'], $form_values['db_user'], $form_values['db_pass'], $form_values['db_host'], $form_values['db_path'], $form_values['settings_file'], $form);
+}
+
+function drupal_install_settings_submit($form_id, $form_values) {
+ $settings['db_url'] = array(
+ 'value' => $form_values['_db_url'],
+ 'required' => TRUE,
+ );
+ $settings['db_prefix'] = array(
+ 'value' => $form_values['db_prefix'],
+ 'required' => TRUE,
+ );
+ drupal_rewrite_settings($settings);
+}
+
+/**
+ * Find all .profile's and allow admin to select which to install.
+ *
+ * @return
+ * The selected profile.
+ */
+function drupal_select_profile() {
+ include_once './includes/file.inc';
+ include_once './includes/form.inc';
+
+ $profiles = file_scan_directory('./profiles', '\.profile$', array('.', '..', 'CVS'), 0, TRUE, 'name', 0);
+ // Don't need to choose profile if only one available
+ if (sizeof($profiles) == 1) {
+ $profile = array_pop($profiles);
+ require_once $profile->filename;
+ return $profile->name;
+ }
+ elseif (sizeof($profiles) > 1) {
+ drupal_maintenance_theme();
+ $form = '';
+ foreach ($profiles as $profile) {
+ include_once($profile->filename);
+ if ($_POST['profile'] == "$profile->name") {
+ return "$profile->name";
+ }
+ // load profile details
+ $function = $profile->name .'_profile_details';
+ if (function_exists($function)) {
+ $details = $function();
+ }
+
+ // If set, used defined name. Otherwise use file name.
+ $name = isset($details['name']) ? $details['name'] : $profile->name;
+
+ // Build a quick form. We can't use the core forms api because we
+ // aren't able to bootstrap Drupal yet.
+ $element = array(
+ '#type' => 'radio',
+ '#name' => 'profile',
+ '#value' => 'default',
+ '#return_value' => "$profile->name",
+ '#title' => "$name",
+ '#description' => $details['description'],
+ '#parents' => array()
+ );
+ $group = theme('radio', $element);
+
+ $element = array(
+ '#value' => $group,
+ );
+ $form .= theme('fieldset', $element);
+
+ }
+ $element = array(
+ '#type' => 'submit',
+ '#name' => 'save',
+ '#value' => 'Save configuration',
+ );
+ $form .= theme('submit', $element);
+
+ drupal_set_title('Select an installation profile');
+ print theme('install_page', '');
+ exit;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/**
+ * Provide module .installs and profiles a chance to request any additional
+ * configuration. Configuration is performed using the core Forms API,
+ * through the use of _install_configure(), _install_configure_validate(), and
+ * _install_configure_submit() hooks.
+ */
+function drupal_install_configure() {
+ global $installed_profile, $installs;
+ require_once "./profiles/$installed_profile.profile";
+
+ $form = array();
+ drupal_set_title('Configuration');
+
+ $modules = $installed_profile .'_profile_modules';
+ $module_list = $modules();
+ $installs = drupal_get_install_files($module_list);
+ foreach ($installs as $install) {
+ require_once $install->filename;
+ $install_configure = $install->name .'_install_configure';
+ if (function_exists("$install_configure")) {
+ $install_configure($form);
+ }
+ }
+
+ $install_configure = $installed_profile .'_install_configure';
+ if (function_exists("$install_configure")) {
+ $install_configure($form);
+ }
+
+ if ($form != array()) {
+ drupal_maintenance_theme();
+ $form['submit'] = array('#type' => 'submit',
+ '#value' => 'Submit');
+
+ print theme('install_page', drupal_get_form('drupal_install_configure_form', $form));
+ exit;
+ }
+}
+
+/**
+ * Calls _install_configure_validate hook where exists in .install and .profile
+ * files. Treat like the standard forms API _validate hook. Note that the
+ * .profile is called last, so it can modify anything done by module .install
+ * files.
+ *
+ * @param $form_id
+ * @param $edit
+ */
+function drupal_install_configure_form_validate($form_id, $edit, $form) {
+ global $profile, $installs;
+
+ foreach ($installs as $install) {
+ require_once $install->filename;
+ $install_configure_validate = $install->name .'_install_configure_validate';
+ if (function_exists("$install_configure_validate")) {
+ $install_configure_validate($form_id, $edit, $form);
+ }
+ }
+
+ $install_configure_validate = $profile .'_install_configure_validate';
+ if (function_exists("$install_configure_validate")) {
+ $install_configure_validate($form_id, $edit);
+ }
+
+}
+
+/**
+ * Calls _install_configure_submit hook where exists in .install and .profile
+ * files. Treat like the standard forms API _submit hook. Note that the
+ * .profile is called last, so it can modify anything done by module .install
+ * files.
+ *
+ * @param $form_id
+ * @param $edit
+ */
+function drupal_install_configure_form_submit($form_id, $edit) {
+ global $profile, $installs;
+
+ foreach ($installs as $install) {
+ require_once $install->filename;
+ $install_configure_submit = $install->name .'_install_configure_submit';
+ if (function_exists("$install_configure_submit")) {
+ $install_configure_submit($form_id, $edit);
+ }
+ }
+
+ $install_configure_submit = $profile .'_install_configure_submit';
+ if (function_exists("$install_configure_submit")) {
+ $install_configure_submit($form_id, $edit);
+ }
+
+ _install_goto('install.php?installed=TRUE');
+}
+
+/**
+ * Get list of all .install files.
+ *
+ * @param $module_list
+ * An array of modules to search for their .install files.
+ */
+function drupal_get_install_files($module_list = array()) {
+ $installs = array();
+ foreach ($module_list as $module) {
+ $installs = array_merge($installs, file_scan_directory('./modules', "^$module.install$", array('.', '..', 'CVS'), 0, TRUE, 'name', 0));
+ }
+ return $installs;
+}
+
+/**
+ * An error page to display when there are no profiles available.
+ */
+function _install_no_profile_error() {
+ drupal_maintenance_theme();
+ drupal_set_title('No profiles available');
+ print theme('install_page', 'We were unable to find any installer profiles. Installer profiles tell us what modules to enable, and what schema to install in the database. A profile is necessary to continue with the installation process.
'); + exit; +} + +/** + * Installed profile. + * + * @param profile + * Name of profile to install. + */ +function drupal_install_profile($profile) { + global $db_type; + + include './includes/module.inc'; + include './includes/file.inc'; + + $profile_file = "./profiles/$profile.profile"; + + if (!isset($profile) || !file_exists($profile_file)) { + _install_no_profile_error(); + } + + require_once($profile_file); + + // Get a list of modules required by this profile + $function = $profile .'_profile_modules'; + $module_list = $function(); + + // Verify that all required modules exist + $modules = array(); + foreach ($module_list as $current) { + $module = file_scan_directory('./modules', "^$current.module$", array('.', '..', 'CVS'), 0, TRUE, 'name', 0); + if (empty($module)) { + drupal_set_message("The $current module is required but was not found. Please move the file $current.module into the modules subdirectory.", 'error'); + } + else { + $modules = array_merge($modules, $module); + } + } + + // Get a list of all .install files + $installs = drupal_get_install_files($module_list); + + // Install schemas for profile and all its modules + $function = $profile .'_install'; + if (function_exists($function)) { + $function(); + } + + foreach ($installs as $install) { + module_invoke($install->name, 'install'); + } + + // Enable the modules required by the profile + db_query("DELETE FROM {system} WHERE type = 'module'"); + db_query("INSERT INTO {system} (filename, name, type, description, status, throttle, bootstrap, schema_version) VALUES('". $module->filename ."', '". $module->name ."', 'module', '', 1, 0, 0, 0)"); + + // Update settings.php to show that the installer has already been run + $settings = array(); + $settings['installed_profile'] = array( + 'value' => $profile, + 'required' => TRUE + ); + drupal_rewrite_settings($settings); +} + +/** + * Page displayed when the installation is complete. Called from install.php. + */ +function drupal_install_complete() { + global $base_url; + + if (!_profile_installed()) { + // The installer hasn't run before, start at the beginning. + _install_goto('install.php'); + } + + require_once './includes/bootstrap.inc'; + drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + drupal_maintenance_theme(); + drupal_set_title(st('%drupal installation complete', array('%drupal' => _install_profile_name()))); + print theme('maintenance_page', st('Congratulations, %drupal has been successfully installed. Please review any warnings or errors that you might see above before continuing on to your new website.', array('%drupal' => _install_profile_name(), '%path' => "$base_url"))); +} + +/** + * Verify the state of the specified file. + * + * @param $file + * The file to check for. + * @param $mask + * An optional bitmask created from various FILE_* constants. + * @param $message_type + * The type of message to create, can be error or status. Passed on to drupal_set_message as second parameter. + * @param $type + * The type of file. Can be file (default), dir, or link. + * @return + * TRUE on success or FALSE on failure. A messsage is set for the latter. + */ +function drupal_verify_install_file($file, $mask = NULL, $message_type = 'error', $type = 'file') { + $return = TRUE; + // Check for files that shouldn't be there + if (isset($mask) && ($mask & FILE_NOT_EXIST) && file_exists($file)) { + return FALSE; + } + // Verify that the file is the type of file it is supposed to be + if (isset($type) && file_exists($file)) { + $check = 'is_'. $type; + if (!function_exists($check) || !$check($file)) { + drupal_set_message(st('%file exists but is not a %type.', array('%type' => $type, '%file' => $file)), $message_type); + $return = FALSE; + } + } + + // Verify file permissions + if (isset($mask)) { + $filetype = ($filetype == 'dir') ? 'Directory' : ucfirst($type); + $masks = array(FILE_EXIST, FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_EXIST, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); + foreach ($masks as $current_mask) { + if ($mask & $current_mask) { + switch ($current_mask) { + case FILE_EXIST: + if (!file_exists($file)) { + if ($filetype == 'Directory') { + drupal_install_mkdir($file, $mask); + } + if (!file_exists($file)) { + drupal_set_message(st('%type %file does not exist.', array('%type' => $filetype, '%file' => $file)), $message_type); + $return = FALSE; + } + } + break; + case FILE_READABLE: + if (!is_readable($file) && !drupal_install_fix_file($file, $mask)) { + drupal_set_message(st('%type %file is not readable.', array('%type' => $filetype, '%file' => $file)), $message_type); + $return = FALSE; + } + break; + case FILE_WRITABLE: + if (!is_writable($file) && !drupal_install_fix_file($file, $mask)) { + drupal_set_message(st('%type %file is not writable.', array('%type' => $filetype, '%file' => $file)), $message_type); + $return = FALSE; + } + break; + case FILE_EXECUTABLE: + if (!is_executable($file) && !drupal_install_fix_file($file, $mask)) { + drupal_set_message(st('%type %file is not executable.', array('%type' => $filetype, '%file' => $file)), $message_type); + $return = FALSE; + } + break; + case FILE_NOT_READABLE: + if (is_readable($file) && !drupal_install_fix_file($file, $mask)) { + drupal_set_message(st('%type %file is readable but should not be.', array('%type' => $filetype, '%file' => $file)), $message_type); + $return = FALSE; + } + break; + case FILE_NOT_WRITABLE: + if (is_writable($file) && !drupal_install_fix_file($file, $mask)) { + drupal_set_message(st('%type %file is writable but should not be.', array('%type' => $filetype, '%file' => $file)), $message_type); + $return = FALSE; + } + break; + case FILE_NOT_EXECUTABLE: + if (is_executable($file) && !drupal_install_fix_file($file, $mask)) { + drupal_set_message(st('%type %file is executable but should not be.', array('%type' => $filetype, '%file' => $file)), $message_type); + $return = FALSE; + } + break; + } + } + } + } + return $return; +} + +/** + * Create a directory with specified permissions. + * + * @param file + * The name of the directory to create; + * @param mask + * The permissions of the directory to create. + * + * @return + * TRUE/FALSE whether or not the directory was successfully created. + */ +function drupal_install_mkdir($file, $mask) { + $mod = 0; + $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); + foreach ($masks as $m) { + if ($mask & $m) { + switch ($m) { + case FILE_READABLE: + $mod += 444; + break; + case FILE_WRITABLE: + $mod += 222; + break; + case FILE_EXECUTABLE: + $mod += 111; + break; + } + } + } + + if (@mkdir($file, intval("0$mod", 8))) { + drupal_set_message("Automatically created directory $file.", 'status'); + return TRUE; + } + else { + drupal_set_message("Failed to automatically create directory $file, insufficient privileges.", 'status'); + } +} + +/** + * Attempt to fix file permissions. + * + * @param $file + * The name of the file with permissions to fix. + * @param $mask + * The desired permissions for the file. + * + * @return + * TRUE/FALSE whether or not we were able to fix the file's permissions. + */ +function drupal_install_fix_file($file, $mask) { + $mod = substr(sprintf('%o', fileperms($file)), -4); + $prefix = substr($mod, 0, 1); + $mod = substr($mod, 1 ,4); + $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); + foreach ($masks as $m) { + if ($mask & $m) { + switch ($m) { + case FILE_READABLE: + if (!is_readable($file)) { + $mod += 444; + } + break; + case FILE_WRITABLE: + if (!is_writable($file)) { + $mod += 222; + } + break; + case FILE_EXECUTABLE: + if (!is_executable($file)) { + $mod += 111; + } + break; + case FILE_NOT_READABLE: + if (is_readable($file)) { + $mod -= 444; + } + break; + case FILE_NOT_WRITABLE: + if (is_writable($file)) { + $mod -= 222; + } + break; + case FILE_NOT_EXECUTABLE: + if (is_executable($file)) { + $mod -= 111; + } + break; + } + } + } + + if (@chmod($file, intval("$prefix$mod", 8))) { + drupal_set_message("Automatically fixed the permissions of file $file.", 'status'); + return TRUE; + } + else { + drupal_set_message("Failed to automatically fix permissions of file $file, insufficient privileges.", 'error'); + return FALSE; + } +} + +?> === modified file 'includes/module.inc' --- includes/module.inc +++ includes/module.inc @@ -37,14 +37,20 @@ function module_iterate($function, $argu * @param $sort * By default, modules are ordered by weight and filename, settings this option * to TRUE, module list will be ordered by module name. + * @param $loaded + * A list of loaded modules, mostly used by external scripts. * @return * An associative array whose keys and values are the names of all loaded * modules. */ -function module_list($refresh = FALSE, $bootstrap = TRUE, $sort = FALSE) { +function module_list($refresh = FALSE, $bootstrap = TRUE, $sort = FALSE, $loaded = NULL) { static $list, $sorted_list; if ($refresh) { + if (isset($loaded)) { + $list = $loaded; + return $list; + } $list = array(); $sorted_list = NULL; } === modified file 'includes/theme.inc' --- includes/theme.inc +++ includes/theme.inc @@ -453,17 +453,62 @@ function theme_maintenance_page($content return $output; } +function theme_install_page($content) { + drupal_set_header('Content-Type: text/html; charset=utf-8'); + theme('add_style', 'misc/maintenance.css'); + drupal_set_html_head(''); + $output = "\n"; + $output .= ''; + $output .= '
'; + $output .= '